From e7a65ba694d84592d190644d8d0ae4ea9137c35d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 30 Dec 2022 15:35:24 +0100 Subject: [PATCH 001/814] hw/mips/malta: Split FPGA LEDs/ASCII display updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to refresh the ASCII bar when a LED is toggled (and vice versa). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-3-philmd@linaro.org> --- hw/mips/malta.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index c0a2e0ab04..e9424150aa 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -106,11 +106,10 @@ static struct _loaderparams { } loaderparams; /* Malta FPGA */ -static void malta_fpga_update_display(void *opaque) +static void malta_fpga_update_display_leds(MaltaFPGAState *s) { char leds_text[9]; int i; - MaltaFPGAState *s = opaque; for (i = 7 ; i >= 0 ; i--) { if (s->leds & (1 << i)) { @@ -123,6 +122,10 @@ static void malta_fpga_update_display(void *opaque) qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); +} + +static void malta_fpga_update_display_ascii(MaltaFPGAState *s) +{ qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); } @@ -457,13 +460,13 @@ static void malta_fpga_write(void *opaque, hwaddr addr, /* LEDBAR Register */ case 0x00408: s->leds = val & 0xff; - malta_fpga_update_display(s); + malta_fpga_update_display_leds(s); break; /* ASCIIWORD Register */ case 0x00410: snprintf(s->display_text, 9, "%08X", (uint32_t)val); - malta_fpga_update_display(s); + malta_fpga_update_display_ascii(s); break; /* ASCIIPOS0 to ASCIIPOS7 Registers */ @@ -476,7 +479,7 @@ static void malta_fpga_write(void *opaque, hwaddr addr, case 0x00448: case 0x00450: s->display_text[(saddr - 0x00418) >> 3] = (char) val; - malta_fpga_update_display(s); + malta_fpga_update_display_ascii(s); break; /* SOFTRES Register */ From 9f81e43f10496bc225a9bbed3d56a26b9f759fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 30 Dec 2022 15:35:24 +0100 Subject: [PATCH 002/814] hw/mips/malta: Trace FPGA LEDs/ASCII display updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FPGA LEDs/ASCII display is mostly used by the bootloader to show very low-level debug info. QEMU connects its output to a character device backend, which is not very practical to correlate with ASM instruction executed, interrupts or MMIO accesses. Also, the display discard the previous states. To ease bootloader debugging experience, add a pair of trace events. Such events can be analyzed over time or diff-ed between different runs. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-4-philmd@linaro.org> --- hw/mips/malta.c | 3 +++ hw/mips/trace-events | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index e9424150aa..44d88a24a7 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -58,6 +58,7 @@ #include "semihosting/semihost.h" #include "hw/mips/cps.h" #include "hw/qdev-clock.h" +#include "trace.h" #define ENVP_PADDR 0x2000 #define ENVP_VADDR cpu_mips_phys_to_kseg0(NULL, ENVP_PADDR) @@ -120,12 +121,14 @@ static void malta_fpga_update_display_leds(MaltaFPGAState *s) } leds_text[8] = '\0'; + trace_malta_fpga_leds(leds_text); qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); } static void malta_fpga_update_display_ascii(MaltaFPGAState *s) { + trace_malta_fpga_display(s->display_text); qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); } diff --git a/hw/mips/trace-events b/hw/mips/trace-events index 13ee731a48..b5b882c6c2 100644 --- a/hw/mips/trace-events +++ b/hw/mips/trace-events @@ -4,3 +4,7 @@ gt64120_write(uint64_t addr, uint64_t value) "gt64120 write 0x%03"PRIx64" value: gt64120_read_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 read %s size:%u value:0x%08" PRIx64 gt64120_write_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 write %s size:%u value:0x%08" PRIx64 gt64120_isd_remap(uint64_t from_length, uint64_t from_addr, uint64_t to_length, uint64_t to_addr) "ISD: 0x%08" PRIx64 "@0x%08" PRIx64 " -> 0x%08" PRIx64 "@0x%08" PRIx64 + +# malta.c +malta_fpga_leds(const char *text) "LEDs %s" +malta_fpga_display(const char *text) "ASCII '%s'" From 65423e6efeac1ee1057870361337c572c941140c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Jan 2023 09:35:22 +0100 Subject: [PATCH 003/814] hw/mips/gt64xxx_pci: Accumulate address space changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single registers access in ISD can produce multiple changes in the address spaces. To reduce computational effort, accumulate these as a single memory transaction. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-5-philmd@linaro.org> --- hw/mips/gt64xxx_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 164866cf3e..65416c7b27 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -282,6 +282,8 @@ static void gt64120_isd_mapping(GT64120State *s) hwaddr start = ((hwaddr)s->regs[GT_ISD] << 21) & 0xFFFE00000ull; hwaddr length = 0x1000; + memory_region_transaction_begin(); + if (s->ISD_length) { memory_region_del_subregion(get_system_memory(), &s->ISD_mem); } @@ -292,10 +294,14 @@ static void gt64120_isd_mapping(GT64120State *s) s->ISD_start = start; s->ISD_length = length; memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem); + + memory_region_transaction_commit(); } static void gt64120_pci_mapping(GT64120State *s) { + memory_region_transaction_begin(); + /* Update PCI0IO mapping */ if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) { /* Unmap old IO address */ @@ -354,6 +360,8 @@ static void gt64120_pci_mapping(GT64120State *s) &s->PCI0M1_mem); } } + + memory_region_transaction_commit(); } static int gt64120_post_load(void *opaque, int version_id) From 145e2198d749ec09a405f1607a9932499b76f1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Jan 2023 10:03:14 +0100 Subject: [PATCH 004/814] hw/mips/gt64xxx_pci: Endian-swap using PCI_HOST_BRIDGE MemoryRegionOps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GT64120's PCI endianness swapping works on little-endian hosts, but doesn't on big-endian ones. Instead of complicating how CFGADDR/CFGDATA registers deal with endianness, use the existing MemoryRegionOps from hw/pci/pci_host.c. Doing so also reduce the access to internal PCI_HOST_BRIDGE fields. Map the PCI_HOST_BRIDGE MemoryRegionOps into the corresponding CFGADDR/CFGDATA regions in the ISD MMIO and remove the unused code in the current ISD read/write handlers. Update the mapping when PCI0_CMD register is accessed (in case the endianness is changed). This allows using the GT64120 on a big-endian host (and boot the MIPS Malta machine in little-endian). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-6-philmd@linaro.org> --- hw/mips/gt64xxx_pci.c | 70 ++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 65416c7b27..81232514c5 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -298,6 +298,50 @@ 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_conf_ops[] = { + &pci_host_conf_be_ops, &pci_host_conf_le_ops + }; + 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 Endianess bit in the CPU + * Configuration Register. See: + * - Table 16: 32-bit PCI Transaction Endianess + * - Table 158: PCI_0 Command, Offset: 0xc00 + */ + if (memory_region_is_mapped(&phb->conf_mem)) { + memory_region_del_subregion(&s->ISD_mem, &phb->conf_mem); + object_unparent(OBJECT(&phb->conf_mem)); + } + memory_region_init_io(&phb->conf_mem, OBJECT(phb), + pci_host_conf_ops[s->regs[GT_PCI0_CMD] & 1], + s, "pci-conf-idx", 4); + memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2, + &phb->conf_mem, 1); + + 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(); @@ -389,7 +433,6 @@ static void gt64120_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { GT64120State *s = opaque; - PCIHostState *phb = PCI_HOST_BRIDGE(s); uint32_t saddr = addr >> 2; trace_gt64120_write(addr, val); @@ -592,6 +635,7 @@ 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: @@ -632,15 +676,9 @@ static void gt64120_writel(void *opaque, hwaddr addr, saddr << 2, size, size << 1, val); break; case GT_PCI0_CFGADDR: - phb->config_reg = val & 0x80fffffc; - break; case GT_PCI0_CFGDATA: - if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { - val = bswap32(val); - } - if (phb->config_reg & (1u << 31)) { - pci_data_write(phb->bus, phb->config_reg, val, 4); - } + /* Mapped via in gt64120_pci_mapping() */ + g_assert_not_reached(); break; /* Interrupts */ @@ -698,7 +736,6 @@ static uint64_t gt64120_readl(void *opaque, hwaddr addr, unsigned size) { GT64120State *s = opaque; - PCIHostState *phb = PCI_HOST_BRIDGE(s); uint32_t val; uint32_t saddr = addr >> 2; @@ -883,17 +920,9 @@ static uint64_t gt64120_readl(void *opaque, /* PCI Internal */ case GT_PCI0_CFGADDR: - val = phb->config_reg; - break; case GT_PCI0_CFGDATA: - if (!(phb->config_reg & (1 << 31))) { - val = 0xffffffff; - } else { - val = pci_data_read(phb->bus, phb->config_reg, 4); - } - if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { - val = bswap32(val); - } + /* Mapped via in gt64120_pci_mapping() */ + g_assert_not_reached(); break; case GT_PCI0_CMD: @@ -1153,6 +1182,7 @@ 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) From 7c032bfbe838c24dcbdc8f9c452553b24f20daad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 10 Mar 2019 02:25:07 +0100 Subject: [PATCH 005/814] hw/mips/Kconfig: Introduce CONFIG_GT64120 to select gt64xxx_pci.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Message-Id: <20221209151533.69516-2-philmd@linaro.org> Reviewed-by: Richard Henderson --- hw/mips/Kconfig | 6 ++++++ hw/mips/meson.build | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 725525358d..d6bbbe7069 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -1,5 +1,6 @@ config MALTA bool + select GT64120 select ISA_SUPERIO config MIPSSIM @@ -59,3 +60,8 @@ config MIPS_BOSTON config FW_CFG_MIPS bool + +config GT64120 + bool + select PCI + select I8259 diff --git a/hw/mips/meson.build b/hw/mips/meson.build index dd0101ad4d..6ccd385df0 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -2,7 +2,8 @@ mips_ss = ss.source_set() mips_ss.add(files('bootloader.c', 'mips_int.c')) mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c')) mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c')) -mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c')) +mips_ss.add(when: 'CONFIG_MALTA', if_true: files('malta.c')) +mips_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64xxx_pci.c')) mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c')) if 'CONFIG_TCG' in config_all From 37e506b69a6791bede30677f05081296f3b77f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 2 Mar 2021 23:42:56 +0100 Subject: [PATCH 006/814] hw/mips/gt64xxx_pci: Let the GT64120 manage the lower 512MiB hole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the comment in the Malta board, the [0x0000.0000-0x2000.0000] range is decoded by the GT64120, so move the "empty_slot" there. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209151533.69516-3-philmd@linaro.org> Reviewed-by: Richard Henderson --- configs/devices/mips-softmmu/common.mak | 1 - hw/mips/Kconfig | 1 + hw/mips/gt64xxx_pci.c | 8 ++++++++ hw/mips/malta.c | 7 ------- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/configs/devices/mips-softmmu/common.mak b/configs/devices/mips-softmmu/common.mak index 88aff94625..a125e74f24 100644 --- a/configs/devices/mips-softmmu/common.mak +++ b/configs/devices/mips-softmmu/common.mak @@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y CONFIG_PFLASH_CFI01=y CONFIG_I8259=y CONFIG_MC146818RTC=y -CONFIG_EMPTY_SLOT=y CONFIG_MIPS_CPS=y CONFIG_MIPS_ITU=y CONFIG_MALTA=y diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index d6bbbe7069..8f7bce38fb 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -64,4 +64,5 @@ config FW_CFG_MIPS config GT64120 bool select PCI + select EMPTY_SLOT select I8259 diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 81232514c5..7ba052a2e0 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -28,6 +28,7 @@ #include "qemu/log.h" #include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" +#include "hw/misc/empty_slot.h" #include "migration/vmstate.h" #include "hw/intc/i8259.h" #include "hw/irq.h" @@ -1200,6 +1201,13 @@ static void gt64120_realize(DeviceState *dev, Error **errp) PCI_DEVFN(18, 0), TYPE_PCI_BUS); pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci"); + + /* + * The whole address space decoded by the GT-64120A doesn't generate + * exception when accessing invalid memory. Create an empty slot to + * emulate this feature. + */ + empty_slot_init("GT64120", 0, 0x20000000); } static void gt64120_pci_realize(PCIDevice *d, Error **errp) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 44d88a24a7..c8fc420e4f 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -53,7 +53,6 @@ #include "sysemu/runstate.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "hw/misc/empty_slot.h" #include "sysemu/kvm.h" #include "semihosting/semihost.h" #include "hw/mips/cps.h" @@ -1399,12 +1398,6 @@ void mips_malta_init(MachineState *machine) /* Northbridge */ dev = sysbus_create_simple("gt64120", -1, NULL); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); - /* - * The whole address space decoded by the GT-64120A doesn't generate - * exception when accessing invalid memory. Create an empty slot to - * emulate this feature. - */ - empty_slot_init("GT64120", 0, 0x20000000); /* Southbridge */ piix4 = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), true, From 81ad24762d4295bbe1e2216b21d1e90b81d351a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Oct 2022 02:00:42 +0200 Subject: [PATCH 007/814] hw/mips/gt64xxx_pci: Manage endian bits with the RegisterFields API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221220113436.14299-4-philmd@linaro.org> Reviewed-by: Richard Henderson --- hw/mips/gt64xxx_pci.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 7ba052a2e0..85bdf5279c 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" +#include "hw/registerfields.h" #include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" #include "hw/misc/empty_slot.h" @@ -41,6 +42,9 @@ #define GT_CPU (0x000 >> 2) #define GT_MULTI (0x120 >> 2) +REG32(GT_CPU, 0x000) +FIELD(GT_CPU, Endianness, 12, 1) + /* CPU Address Decode */ #define GT_SCS10LD (0x008 >> 2) #define GT_SCS10HD (0x010 >> 2) @@ -210,6 +214,17 @@ #define GT_PCI0_CFGADDR (0xcf8 >> 2) #define GT_PCI0_CFGDATA (0xcfc >> 2) +REG32(GT_PCI0_CMD, 0xc00) +FIELD(GT_PCI0_CMD, MByteSwap, 0, 1) +FIELD(GT_PCI0_CMD, SByteSwap, 16, 1) +#define R_GT_PCI0_CMD_ByteSwap_MASK \ + (R_GT_PCI0_CMD_MByteSwap_MASK | R_GT_PCI0_CMD_SByteSwap_MASK) +REG32(GT_PCI1_CMD, 0xc80) +FIELD(GT_PCI1_CMD, MByteSwap, 0, 1) +FIELD(GT_PCI1_CMD, SByteSwap, 16, 1) +#define R_GT_PCI1_CMD_ByteSwap_MASK \ + (R_GT_PCI1_CMD_MByteSwap_MASK | R_GT_PCI1_CMD_SByteSwap_MASK) + /* Interrupts */ #define GT_INTRCAUSE (0xc18 >> 2) #define GT_INTRMASK (0xc1c >> 2) @@ -1020,15 +1035,16 @@ static const MemoryRegionOps isd_mem_ops = { static void gt64120_reset(DeviceState *dev) { GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); +#if TARGET_BIG_ENDIAN + bool cpu_little_endian = false; +#else + bool cpu_little_endian = true; +#endif /* FIXME: Malta specific hw assumptions ahead */ /* CPU Configuration */ -#if TARGET_BIG_ENDIAN - s->regs[GT_CPU] = 0x00000000; -#else - s->regs[GT_CPU] = 0x00001000; -#endif + s->regs[GT_CPU] = cpu_little_endian ? R_GT_CPU_Endianness_MASK : 0; s->regs[GT_MULTI] = 0x00000003; /* CPU Address decode */ @@ -1135,11 +1151,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_TC_CONTROL] = 0x00000000; /* PCI Internal */ -#if TARGET_BIG_ENDIAN - s->regs[GT_PCI0_CMD] = 0x00000000; -#else - s->regs[GT_PCI0_CMD] = 0x00010001; -#endif + s->regs[GT_PCI0_CMD] = cpu_little_endian ? R_GT_PCI0_CMD_ByteSwap_MASK : 0; s->regs[GT_PCI0_TOR] = 0x0000070f; s->regs[GT_PCI0_BS_SCS10] = 0x00fff000; s->regs[GT_PCI0_BS_SCS32] = 0x00fff000; @@ -1156,11 +1168,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000; s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000; s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000; -#if TARGET_BIG_ENDIAN - s->regs[GT_PCI1_CMD] = 0x00000000; -#else - s->regs[GT_PCI1_CMD] = 0x00010001; -#endif + s->regs[GT_PCI1_CMD] = cpu_little_endian ? R_GT_PCI1_CMD_ByteSwap_MASK : 0; s->regs[GT_PCI1_TOR] = 0x0000070f; s->regs[GT_PCI1_BS_SCS10] = 0x00fff000; s->regs[GT_PCI1_BS_SCS32] = 0x00fff000; From a699b915ded075b6253bebf50ec5dc2040d23612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Jun 2019 17:06:24 +0200 Subject: [PATCH 008/814] hw/mips/gt64xxx_pci: Add a 'cpu-little-endian' qdev property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This device does not have to be TARGET-dependent. Add a 'cpu_big_endian' property which sets the byte-swapping options if required. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221220113436.14299-5-philmd@linaro.org> Reviewed-by: Richard Henderson --- hw/mips/gt64xxx_pci.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 85bdf5279c..79c15a5e3a 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" +#include "hw/qdev-properties.h" #include "hw/registerfields.h" #include "hw/pci/pci_device.h" #include "hw/pci/pci_host.h" @@ -256,6 +257,9 @@ struct GT64120State { PCI_MAPPING_ENTRY(ISD); MemoryRegion pci0_mem; AddressSpace pci0_mem_as; + + /* properties */ + bool cpu_little_endian; }; /* Adjust range to avoid touching space which isn't mappable via PCI */ @@ -1035,16 +1039,11 @@ static const MemoryRegionOps isd_mem_ops = { static void gt64120_reset(DeviceState *dev) { GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); -#if TARGET_BIG_ENDIAN - bool cpu_little_endian = false; -#else - bool cpu_little_endian = true; -#endif /* FIXME: Malta specific hw assumptions ahead */ /* CPU Configuration */ - s->regs[GT_CPU] = cpu_little_endian ? R_GT_CPU_Endianness_MASK : 0; + s->regs[GT_CPU] = s->cpu_little_endian ? R_GT_CPU_Endianness_MASK : 0; s->regs[GT_MULTI] = 0x00000003; /* CPU Address decode */ @@ -1151,7 +1150,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_TC_CONTROL] = 0x00000000; /* PCI Internal */ - s->regs[GT_PCI0_CMD] = cpu_little_endian ? R_GT_PCI0_CMD_ByteSwap_MASK : 0; + s->regs[GT_PCI0_CMD] = s->cpu_little_endian ? R_GT_PCI0_CMD_ByteSwap_MASK : 0; s->regs[GT_PCI0_TOR] = 0x0000070f; s->regs[GT_PCI0_BS_SCS10] = 0x00fff000; s->regs[GT_PCI0_BS_SCS32] = 0x00fff000; @@ -1168,7 +1167,7 @@ static void gt64120_reset(DeviceState *dev) s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000; s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000; s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000; - s->regs[GT_PCI1_CMD] = cpu_little_endian ? R_GT_PCI1_CMD_ByteSwap_MASK : 0; + s->regs[GT_PCI1_CMD] = s->cpu_little_endian ? R_GT_PCI1_CMD_ByteSwap_MASK : 0; s->regs[GT_PCI1_TOR] = 0x0000070f; s->regs[GT_PCI1_BS_SCS10] = 0x00fff000; s->regs[GT_PCI1_BS_SCS32] = 0x00fff000; @@ -1262,11 +1261,18 @@ static const TypeInfo gt64120_pci_info = { }, }; +static Property gt64120_properties[] = { + DEFINE_PROP_BOOL("cpu-little-endian", GT64120State, + cpu_little_endian, !TARGET_BIG_ENDIAN), + DEFINE_PROP_END_OF_LIST(), +}; + static void gt64120_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + device_class_set_props(dc, gt64120_properties); dc->realize = gt64120_realize; dc->reset = gt64120_reset; dc->vmsd = &vmstate_gt64120; From fae45dd53dcf4029e30b0915efcc62dfd56bdee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Oct 2022 01:54:06 +0200 Subject: [PATCH 009/814] hw/mips/malta: Explicit GT64120 endianness upon device creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate the controller endianess from the machine, setting the "cpu-little-endian" property. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209151533.69516-6-philmd@linaro.org> Reviewed-by: Richard Henderson --- hw/mips/malta.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index c8fc420e4f..f959bce673 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -1396,7 +1396,9 @@ void mips_malta_init(MachineState *machine) stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420); /* Northbridge */ - dev = sysbus_create_simple("gt64120", -1, NULL); + dev = qdev_new("gt64120"); + qdev_prop_set_bit(dev, "cpu-little-endian", !be); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); /* Southbridge */ From 90f7d0b4940be29259f6977d2df2ca09495680e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 May 2021 15:41:49 +0200 Subject: [PATCH 010/814] hw/mips/meson: Make gt64xxx_pci.c endian-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The single machine using this device explicitly sets its endianness. We don't need to set a default. This allow us to remove the target specificity from the build system. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209151533.69516-7-philmd@linaro.org> Reviewed-by: Richard Henderson --- hw/mips/gt64xxx_pci.c | 2 +- hw/mips/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 79c15a5e3a..f226d03420 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -1263,7 +1263,7 @@ static const TypeInfo gt64120_pci_info = { static Property gt64120_properties[] = { DEFINE_PROP_BOOL("cpu-little-endian", GT64120State, - cpu_little_endian, !TARGET_BIG_ENDIAN), + cpu_little_endian, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/mips/meson.build b/hw/mips/meson.build index 6ccd385df0..152103f15f 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -3,7 +3,7 @@ mips_ss.add(files('bootloader.c', 'mips_int.c')) mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c')) mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c')) mips_ss.add(when: 'CONFIG_MALTA', if_true: files('malta.c')) -mips_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64xxx_pci.c')) +softmmu_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64xxx_pci.c')) mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c')) if 'CONFIG_TCG' in config_all From a7db759ef70fdc6ec7e79c603d3daf7c87113bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 13 Jan 2023 09:20:12 +0100 Subject: [PATCH 011/814] hw/mips/gt64xxx_pci: Move it to hw/pci-host/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GT-64120 is a north-bridge, and it is not MIPS specific. Move it with the other north-bridge devices. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209151533.69516-8-philmd@linaro.org> Reviewed-by: Richard Henderson --- MAINTAINERS | 2 +- hw/mips/Kconfig | 6 ------ hw/mips/meson.build | 1 - hw/mips/trace-events | 7 ------- hw/pci-host/Kconfig | 6 ++++++ hw/{mips/gt64xxx_pci.c => pci-host/gt64120.c} | 0 hw/pci-host/meson.build | 1 + hw/pci-host/trace-events | 7 +++++++ 8 files changed, 15 insertions(+), 15 deletions(-) rename hw/{mips/gt64xxx_pci.c => pci-host/gt64120.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 5606e5dbd2..a670fbc926 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1241,7 +1241,7 @@ S: Odd Fixes F: hw/isa/piix4.c F: hw/acpi/piix4.c F: hw/mips/malta.c -F: hw/mips/gt64xxx_pci.c +F: hw/pci-host/gt64120.c F: include/hw/southbridge/piix.h F: tests/avocado/linux_ssh_mips_malta.py F: tests/avocado/machine_mips_malta.py diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 8f7bce38fb..7a55143f8a 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -60,9 +60,3 @@ config MIPS_BOSTON config FW_CFG_MIPS bool - -config GT64120 - bool - select PCI - select EMPTY_SLOT - select I8259 diff --git a/hw/mips/meson.build b/hw/mips/meson.build index 152103f15f..900613fc08 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -3,7 +3,6 @@ mips_ss.add(files('bootloader.c', 'mips_int.c')) mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c')) mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c')) mips_ss.add(when: 'CONFIG_MALTA', if_true: files('malta.c')) -softmmu_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64xxx_pci.c')) mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c')) if 'CONFIG_TCG' in config_all diff --git a/hw/mips/trace-events b/hw/mips/trace-events index b5b882c6c2..4a4e5fe1a1 100644 --- a/hw/mips/trace-events +++ b/hw/mips/trace-events @@ -1,10 +1,3 @@ -# gt64xxx_pci.c -gt64120_read(uint64_t addr, uint64_t value) "gt64120 read 0x%03"PRIx64" value:0x%08" PRIx64 -gt64120_write(uint64_t addr, uint64_t value) "gt64120 write 0x%03"PRIx64" value:0x%08" PRIx64 -gt64120_read_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 read %s size:%u value:0x%08" PRIx64 -gt64120_write_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 write %s size:%u value:0x%08" PRIx64 -gt64120_isd_remap(uint64_t from_length, uint64_t from_addr, uint64_t to_length, uint64_t to_addr) "ISD: 0x%08" PRIx64 "@0x%08" PRIx64 " -> 0x%08" PRIx64 "@0x%08" PRIx64 - # malta.c malta_fpga_leds(const char *text) "LEDs %s" malta_fpga_display(const char *text) "ASCII '%s'" diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 38fd2ee8f3..a07070eddf 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -81,3 +81,9 @@ config MV64361 config DINO bool select PCI + +config GT64120 + bool + select PCI + select EMPTY_SLOT + select I8259 diff --git a/hw/mips/gt64xxx_pci.c b/hw/pci-host/gt64120.c similarity index 100% rename from hw/mips/gt64xxx_pci.c rename to hw/pci-host/gt64120.c diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index e832babc9d..9a813d552e 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -1,6 +1,7 @@ pci_ss = ss.source_set() pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c')) pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c')) +pci_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64120.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: files('designware.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c')) pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], if_true: files('gpex-acpi.c')) diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 437e66ff50..9d216bb89f 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -6,6 +6,13 @@ bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address i # grackle.c grackle_set_irq(int irq_num, int level) "set_irq num %d level %d" +# gt64120.c +gt64120_read(uint64_t addr, uint64_t value) "gt64120 read 0x%03"PRIx64" value:0x%08" PRIx64 +gt64120_write(uint64_t addr, uint64_t value) "gt64120 write 0x%03"PRIx64" value:0x%08" PRIx64 +gt64120_read_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 read %s size:%u value:0x%08" PRIx64 +gt64120_write_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 write %s size:%u value:0x%08" PRIx64 +gt64120_isd_remap(uint64_t from_length, uint64_t from_addr, uint64_t to_length, uint64_t to_addr) "ISD: 0x%08" PRIx64 "@0x%08" PRIx64 " -> 0x%08" PRIx64 "@0x%08" PRIx64 + # mv64361.c mv64361_region_map(const char *name, uint64_t poffs, uint64_t size, uint64_t moffs) "Mapping %s 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 mv64361_region_enable(const char *op, int num) "Should %s region %d" From 14c2b18414ee88a175b4855361dfbdaa836e0491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 30 Dec 2022 21:53:42 +0100 Subject: [PATCH 012/814] tests/avocado: Add tests booting YAMON ROM on MIPS Malta machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add quick tests booting YAMON: $ avocado --show=app,console run -t machine:malta tests/avocado/machine_mips_malta.py (1/2) tests/avocado/machine_mips_malta.py:MaltaMachine.test_mipsel_malta_yamon: console: YAMON ROM Monitor, Revision 02.22. console: Copyright (c) 1999-2007 MIPS Technologies, Inc. - All Rights Reserved. console: For a list of available commands, type 'help'. console: Compilation time = May 24 2013 12:16:34 (pburton) console: Board type/revision = 0x02 (Malta) / 0x00 console: Core board type/revision = 0x01 (CoreLV) / 0x00 console: System controller/revision = Galileo / GT_64120A-B-0 console: FPGA revision = 0x0000 console: MAC address = ff.ff.ff.ff.ff.ff console: Board S/N = 0123456789 console: PCI bus frequency = 33.33 MHz console: Processor Company ID/options = 0x01 (MIPS Technologies, Inc.) / 0x00 console: Processor ID/revision = 0x93 (MIPS 24Kf) / 0x00 console: Endianness = Little console: CPU/Bus frequency = 333 MHz / 419 MHz console: Coherency = None console: Flash memory size = 4 MByte console: SDRAM size = 128 MByte console: First free SDRAM address = 0x800c32f0 console: WARNING: Environment variable flash area is invalid! console: HINT : Perform "erase -e" console: YAMON> PASS (1.88 s) (2/2) tests/avocado/machine_mips_malta.py:MaltaMachine.test_mips64el_malta_yamon: ... console: System controller/revision = Galileo / GT_64120A-B-0 console: Processor Company ID/options = 0x01 (MIPS Technologies, Inc.) / 0x00 console: Processor ID/revision = 0x82 (MIPS 20Kc) / 0xa0 ... console: YAMON> PASS (1.89 s) RESULTS : PASS 2 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0 JOB TIME : 4.57 s YAMON does some endian-swapped acceses on the ISD<->PCI CFG/DATA registers. These tests are useful to debug cross-endianness issues, in particular on big-endian host. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-7-philmd@linaro.org> --- tests/avocado/machine_mips_malta.py | 47 ++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/avocado/machine_mips_malta.py b/tests/avocado/machine_mips_malta.py index f1895d59f3..92233451c5 100644 --- a/tests/avocado/machine_mips_malta.py +++ b/tests/avocado/machine_mips_malta.py @@ -11,11 +11,13 @@ import os import gzip import logging -from avocado import skipUnless -from avocado_qemu import QemuSystemTest -from avocado_qemu import wait_for_console_pattern -from avocado.utils import archive from avocado import skipIf +from avocado import skipUnless +from avocado.utils import archive +from avocado_qemu import QemuSystemTest +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 NUMPY_AVAILABLE = True @@ -118,3 +120,40 @@ class MaltaMachineFramebuffer(QemuSystemTest): :avocado: tags=mips:smp """ self.do_test_i6400_framebuffer_logo(8) + +class MaltaMachine(QemuSystemTest): + + def do_test_yamon(self): + rom_url = ('http://www.imgtec.com/tools/mips-tools/downloads/' + 'yamon/yamon-bin-02.22.zip') + rom_hash = '8da7ecddbc5312704b8b324341ee238189bde480' + zip_path = self.fetch_asset(rom_url, asset_hash=rom_hash) + + archive.extract(zip_path, self.workdir) + yamon_path = os.path.join(self.workdir, 'yamon-02.22.bin') + + self.vm.set_console() + self.vm.add_args('-bios', yamon_path) + self.vm.launch() + + prompt = 'YAMON>' + pattern = 'YAMON ROM Monitor' + interrupt_interactive_console_until_pattern(self, pattern, prompt) + wait_for_console_pattern(self, prompt) + self.vm.shutdown() + + def test_mipsel_malta_yamon(self): + """ + :avocado: tags=arch:mipsel + :avocado: tags=machine:malta + :avocado: tags=endian:little + """ + self.do_test_yamon() + + def test_mips64el_malta_yamon(self): + """ + :avocado: tags=arch:mips64el + :avocado: tags=machine:malta + :avocado: tags=endian:little + """ + self.do_test_yamon() From cd5066f8618bc6c80ec9088923c58f4a42ab0e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Nov 2022 16:24:39 +0100 Subject: [PATCH 013/814] hw/mips/bootloader: Handle buffers as opaque arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is irrelevant to the API what the buffers to fill are made of. In particular, some MIPS ISA have 16-bit wide instructions. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-2-philmd@linaro.org> --- hw/mips/bootloader.c | 55 +++++++++++++++++++++--------------- hw/mips/boston.c | 2 +- hw/mips/fuloong2e.c | 2 +- hw/mips/malta.c | 19 +++++++------ include/hw/mips/bootloader.h | 10 +++---- 5 files changed, 50 insertions(+), 38 deletions(-) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index f5f42f2bf2..21ffd4d772 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -55,16 +55,20 @@ static bool bootcpu_supports_isa(uint64_t isa_mask) } /* Base types */ -static void bl_gen_nop(uint32_t **p) +static void bl_gen_nop(void **ptr) { - stl_p(*p, 0); - *p = *p + 1; + uint32_t *p = *ptr; + + stl_p(p, 0); + p++; + *ptr = p; } -static void bl_gen_r_type(uint32_t **p, uint8_t opcode, +static void bl_gen_r_type(void **ptr, uint8_t opcode, bl_reg rs, bl_reg rt, bl_reg rd, uint8_t shift, uint8_t funct) { + uint32_t *p = *ptr; uint32_t insn = 0; insn = deposit32(insn, 26, 6, opcode); @@ -74,13 +78,16 @@ static void bl_gen_r_type(uint32_t **p, uint8_t opcode, insn = deposit32(insn, 6, 5, shift); insn = deposit32(insn, 0, 6, funct); - stl_p(*p, insn); - *p = *p + 1; + stl_p(p, insn); + p++; + + *ptr = p; } -static void bl_gen_i_type(uint32_t **p, uint8_t opcode, +static void bl_gen_i_type(void **ptr, uint8_t opcode, bl_reg rs, bl_reg rt, uint16_t imm) { + uint32_t *p = *ptr; uint32_t insn = 0; insn = deposit32(insn, 26, 6, opcode); @@ -88,12 +95,14 @@ static void bl_gen_i_type(uint32_t **p, uint8_t opcode, insn = deposit32(insn, 16, 5, rt); insn = deposit32(insn, 0, 16, imm); - stl_p(*p, insn); - *p = *p + 1; + stl_p(p, insn); + p++; + + *ptr = p; } /* Single instructions */ -static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa) +static void bl_gen_dsll(void **p, bl_reg rd, bl_reg rt, uint8_t sa) { if (bootcpu_supports_isa(ISA_MIPS3)) { bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38); @@ -102,28 +111,28 @@ static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa) } } -static void bl_gen_jalr(uint32_t **p, bl_reg rs) +static void bl_gen_jalr(void **p, bl_reg rs) { bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09); } -static void bl_gen_lui(uint32_t **p, bl_reg rt, uint16_t imm) +static void bl_gen_lui(void **p, bl_reg rt, uint16_t imm) { /* R6: It's a alias of AUI with RS = 0 */ bl_gen_i_type(p, 0x0f, 0, rt, imm); } -static void bl_gen_ori(uint32_t **p, bl_reg rt, bl_reg rs, uint16_t imm) +static void bl_gen_ori(void **p, bl_reg rt, bl_reg rs, uint16_t imm) { bl_gen_i_type(p, 0x0d, rs, rt, imm); } -static void bl_gen_sw(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset) +static void bl_gen_sw(void **p, bl_reg rt, uint8_t base, uint16_t offset) { bl_gen_i_type(p, 0x2b, base, rt, offset); } -static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset) +static void bl_gen_sd(void **p, bl_reg rt, uint8_t base, uint16_t offset) { if (bootcpu_supports_isa(ISA_MIPS3)) { bl_gen_i_type(p, 0x3f, base, rt, offset); @@ -133,13 +142,13 @@ static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset) } /* Pseudo instructions */ -static void bl_gen_li(uint32_t **p, bl_reg rt, uint32_t imm) +static void bl_gen_li(void **p, bl_reg rt, uint32_t imm) { bl_gen_lui(p, rt, extract32(imm, 16, 16)); bl_gen_ori(p, rt, rt, extract32(imm, 0, 16)); } -static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm) +static void bl_gen_dli(void **p, bl_reg rt, uint64_t imm) { bl_gen_li(p, rt, extract64(imm, 32, 32)); bl_gen_dsll(p, rt, rt, 16); @@ -148,7 +157,7 @@ static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm) bl_gen_ori(p, rt, rt, extract64(imm, 0, 16)); } -static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm) +static void bl_gen_load_ulong(void **p, bl_reg rt, target_ulong imm) { if (bootcpu_supports_isa(ISA_MIPS3)) { bl_gen_dli(p, rt, imm); /* 64bit */ @@ -158,14 +167,14 @@ static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm) } /* Helpers */ -void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr) +void bl_gen_jump_to(void **p, target_ulong jump_addr) { bl_gen_load_ulong(p, BL_REG_T9, jump_addr); bl_gen_jalr(p, BL_REG_T9); bl_gen_nop(p); /* delay slot */ } -void bl_gen_jump_kernel(uint32_t **p, +void bl_gen_jump_kernel(void **p, bool set_sp, target_ulong sp, bool set_a0, target_ulong a0, bool set_a1, target_ulong a1, @@ -192,7 +201,7 @@ void bl_gen_jump_kernel(uint32_t **p, bl_gen_jump_to(p, kernel_addr); } -void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val) +void bl_gen_write_ulong(void **p, target_ulong addr, target_ulong val) { bl_gen_load_ulong(p, BL_REG_K0, val); bl_gen_load_ulong(p, BL_REG_K1, addr); @@ -203,14 +212,14 @@ void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val) } } -void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val) +void bl_gen_write_u32(void **p, target_ulong addr, uint32_t val) { bl_gen_li(p, BL_REG_K0, val); bl_gen_load_ulong(p, BL_REG_K1, addr); bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0); } -void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val) +void bl_gen_write_u64(void **p, target_ulong addr, uint64_t val) { bl_gen_dli(p, BL_REG_K0, val); bl_gen_load_ulong(p, BL_REG_K1, addr); diff --git a/hw/mips/boston.c b/hw/mips/boston.c index edda87e23c..b6dd9fb200 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -323,7 +323,7 @@ static void boston_register_types(void) } type_init(boston_register_types) -static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr) +static void gen_firmware(void *p, hwaddr kernel_entry, hwaddr fdt_addr) { uint64_t regaddr; diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index 34befa5dd5..cfc8ca6ae4 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -179,7 +179,7 @@ static void write_bootloader(CPUMIPSState *env, uint8_t *base, /* Second part of the bootloader */ p = (uint32_t *)(base + 0x040); - bl_gen_jump_kernel(&p, + bl_gen_jump_kernel((void **)&p, true, ENVP_VADDR - 64, true, 2, true, ENVP_VADDR, true, ENVP_VADDR + 8, diff --git a/hw/mips/malta.c b/hw/mips/malta.c index f959bce673..b5b62e7245 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -844,6 +844,7 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, uint64_t kernel_entry) { uint32_t *p; + void *v; /* Small bootloader */ p = (uint32_t *)base; @@ -886,38 +887,39 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, #else #define cpu_to_gt32 cpu_to_be32 #endif + v = p; /* move GT64120 registers from 0x14000000 to 0x1be00000 */ - bl_gen_write_u32(&p, /* GT_ISD */ + bl_gen_write_u32(&v, /* GT_ISD */ cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), cpu_to_gt32(0x1be00000 << 3)); /* setup MEM-to-PCI0 mapping */ /* setup PCI0 io window to 0x18000000-0x181fffff */ - bl_gen_write_u32(&p, /* GT_PCI0IOLD */ + bl_gen_write_u32(&v, /* GT_PCI0IOLD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), cpu_to_gt32(0x18000000 << 3)); - bl_gen_write_u32(&p, /* GT_PCI0IOHD */ + bl_gen_write_u32(&v, /* GT_PCI0IOHD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), cpu_to_gt32(0x08000000 << 3)); /* setup PCI0 mem windows */ - bl_gen_write_u32(&p, /* GT_PCI0M0LD */ + bl_gen_write_u32(&v, /* GT_PCI0M0LD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), cpu_to_gt32(0x10000000 << 3)); - bl_gen_write_u32(&p, /* GT_PCI0M0HD */ + bl_gen_write_u32(&v, /* GT_PCI0M0HD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), cpu_to_gt32(0x07e00000 << 3)); - bl_gen_write_u32(&p, /* GT_PCI0M1LD */ + bl_gen_write_u32(&v, /* GT_PCI0M1LD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), cpu_to_gt32(0x18200000 << 3)); - bl_gen_write_u32(&p, /* GT_PCI0M1HD */ + bl_gen_write_u32(&v, /* GT_PCI0M1HD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), cpu_to_gt32(0x0bc00000 << 3)); #undef cpu_to_gt32 - bl_gen_jump_kernel(&p, + bl_gen_jump_kernel(&v, true, ENVP_VADDR - 64, /* * If semihosting is used, arguments have already been @@ -928,6 +930,7 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, true, ENVP_VADDR + 8, true, loaderparams.ram_low_size, kernel_entry); + p = v; /* YAMON subroutines */ p = (uint32_t *) (base + 0x800); diff --git a/include/hw/mips/bootloader.h b/include/hw/mips/bootloader.h index fffb0b7da8..c32f6c2835 100644 --- a/include/hw/mips/bootloader.h +++ b/include/hw/mips/bootloader.h @@ -11,16 +11,16 @@ #include "exec/cpu-defs.h" -void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr); -void bl_gen_jump_kernel(uint32_t **p, +void bl_gen_jump_to(void **ptr, target_ulong jump_addr); +void bl_gen_jump_kernel(void **ptr, bool set_sp, target_ulong sp, bool set_a0, target_ulong a0, bool set_a1, target_ulong a1, bool set_a2, target_ulong a2, bool set_a3, target_ulong a3, target_ulong kernel_addr); -void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val); -void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val); -void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val); +void bl_gen_write_ulong(void **ptr, target_ulong addr, target_ulong val); +void bl_gen_write_u32(void **ptr, target_ulong addr, uint32_t val); +void bl_gen_write_u64(void **ptr, target_ulong addr, uint64_t val); #endif From cf386ca8ab20ecad5efa535f3d48750df740da39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Nov 2022 16:25:46 +0100 Subject: [PATCH 014/814] hw/mips/bootloader: Implement nanoMIPS NOP opcode generator 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: <20221211204533.85359-3-philmd@linaro.org> --- hw/mips/bootloader.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index 21ffd4d772..0035f37335 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -54,14 +54,30 @@ static bool bootcpu_supports_isa(uint64_t isa_mask) return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask); } +static void st_nm32_p(void **ptr, uint32_t insn) +{ + uint16_t *p = *ptr; + + stw_p(p, insn >> 16); + p++; + stw_p(p, insn >> 0); + p++; + + *ptr = p; +} + /* Base types */ static void bl_gen_nop(void **ptr) { - uint32_t *p = *ptr; + if (bootcpu_supports_isa(ISA_NANOMIPS32)) { + st_nm32_p(ptr, 0x8000c000); + } else { + uint32_t *p = *ptr; - stl_p(p, 0); - p++; - *ptr = p; + stl_p(p, 0); + p++; + *ptr = p; + } } static void bl_gen_r_type(void **ptr, uint8_t opcode, From 73be38cbe34df90be4ab9618e62859fa074015ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:33:52 +0100 Subject: [PATCH 015/814] hw/mips/bootloader: Implement nanoMIPS SW opcode generator 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: <20221211204533.85359-4-philmd@linaro.org> --- hw/mips/bootloader.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index 0035f37335..3e1e73360f 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -143,9 +143,27 @@ static void bl_gen_ori(void **p, bl_reg rt, bl_reg rs, uint16_t imm) bl_gen_i_type(p, 0x0d, rs, rt, imm); } +static void bl_gen_sw_nm(void **ptr, bl_reg rt, uint8_t rs, uint16_t ofs12) +{ + uint32_t insn = 0; + + assert(extract32(ofs12, 0, 12) == ofs12); + insn = deposit32(insn, 26, 6, 0b100001); + insn = deposit32(insn, 21, 5, rt); + insn = deposit32(insn, 16, 5, rs); + insn = deposit32(insn, 12, 4, 0b1001); + insn = deposit32(insn, 0, 12, ofs12); + + st_nm32_p(ptr, insn); +} + static void bl_gen_sw(void **p, bl_reg rt, uint8_t base, uint16_t offset) { - bl_gen_i_type(p, 0x2b, base, rt, offset); + if (bootcpu_supports_isa(ISA_NANOMIPS32)) { + bl_gen_sw_nm(p, rt, base, offset); + } else { + bl_gen_i_type(p, 0x2b, base, rt, offset); + } } static void bl_gen_sd(void **p, bl_reg rt, uint8_t base, uint16_t offset) From 5d380e4ca898e7f0ebd436e255a7da4869b15a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:34:09 +0100 Subject: [PATCH 016/814] hw/mips/bootloader: Implement nanoMIPS LI (LUI+ORI) opcode generator 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: <20221211204533.85359-5-philmd@linaro.org> --- hw/mips/bootloader.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index 3e1e73360f..9fc926d83f 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -132,12 +132,39 @@ static void bl_gen_jalr(void **p, bl_reg rs) bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09); } +static void bl_gen_lui_nm(void **ptr, bl_reg rt, uint32_t imm20) +{ + uint32_t insn = 0; + + assert(extract32(imm20, 0, 20) == imm20); + insn = deposit32(insn, 26, 6, 0b111000); + insn = deposit32(insn, 21, 5, rt); + insn = deposit32(insn, 12, 9, extract32(imm20, 0, 9)); + insn = deposit32(insn, 2, 10, extract32(imm20, 9, 10)); + insn = deposit32(insn, 0, 1, sextract32(imm20, 19, 1)); + + st_nm32_p(ptr, insn); +} + static void bl_gen_lui(void **p, bl_reg rt, uint16_t imm) { /* R6: It's a alias of AUI with RS = 0 */ bl_gen_i_type(p, 0x0f, 0, rt, imm); } +static void bl_gen_ori_nm(void **ptr, bl_reg rt, bl_reg rs, uint16_t imm12) +{ + uint32_t insn = 0; + + assert(extract32(imm12, 0, 12) == imm12); + insn = deposit32(insn, 26, 6, 0b100000); + insn = deposit32(insn, 21, 5, rt); + insn = deposit32(insn, 16, 5, rs); + insn = deposit32(insn, 0, 12, imm12); + + st_nm32_p(ptr, insn); +} + static void bl_gen_ori(void **p, bl_reg rt, bl_reg rs, uint16_t imm) { bl_gen_i_type(p, 0x0d, rs, rt, imm); @@ -178,8 +205,13 @@ static void bl_gen_sd(void **p, bl_reg rt, uint8_t base, uint16_t offset) /* Pseudo instructions */ static void bl_gen_li(void **p, bl_reg rt, uint32_t imm) { - bl_gen_lui(p, rt, extract32(imm, 16, 16)); - bl_gen_ori(p, rt, rt, extract32(imm, 0, 16)); + if (bootcpu_supports_isa(ISA_NANOMIPS32)) { + bl_gen_lui_nm(p, rt, extract32(imm, 12, 20)); + bl_gen_ori_nm(p, rt, rt, extract32(imm, 0, 12)); + } else { + bl_gen_lui(p, rt, extract32(imm, 16, 16)); + bl_gen_ori(p, rt, rt, extract32(imm, 0, 16)); + } } static void bl_gen_dli(void **p, bl_reg rt, uint64_t imm) From 9356a2d2be024480aa7f65a598f8c8283f04faa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 19:55:41 +0100 Subject: [PATCH 017/814] hw/mips/bootloader: Implement nanoMIPS JALRc opcode generator 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: <20221211204533.85359-6-philmd@linaro.org> --- hw/mips/bootloader.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/mips/bootloader.c b/hw/mips/bootloader.c index 9fc926d83f..1dd6ef2096 100644 --- a/hw/mips/bootloader.c +++ b/hw/mips/bootloader.c @@ -129,7 +129,17 @@ static void bl_gen_dsll(void **p, bl_reg rd, bl_reg rt, uint8_t sa) static void bl_gen_jalr(void **p, bl_reg rs) { - bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09); + if (bootcpu_supports_isa(ISA_NANOMIPS32)) { + uint32_t insn = 0; + + insn = deposit32(insn, 26, 6, 0b010010); /* JALRC */ + insn = deposit32(insn, 21, 5, BL_REG_RA); + insn = deposit32(insn, 16, 5, rs); + + st_nm32_p(p, insn); + } else { + bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09); + } } static void bl_gen_lui_nm(void **ptr, bl_reg rt, uint32_t imm20) From 391a2bdae99cb09e2cf88337898cb53385bddcc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:42:23 +0100 Subject: [PATCH 018/814] hw/mips/malta: Use bootloader generator API for nanoMIPS CPUs (1/5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to how commit 0c8427baf0 ("hw/mips/malta: Use bootloader helper to set BAR registers") converted write_bootloader(), convert the equivalent write_bootloader_nanomips(), allowing us to modify the bootloader code more easily in the future. Part 1/5: Convert PCI0 MEM1 BAR setup Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-7-philmd@linaro.org> --- hw/mips/malta.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index b5b62e7245..a496053a9a 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -620,6 +620,7 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, uint64_t kernel_entry) { uint16_t *p; + void *v; /* Small bootloader */ p = (uint16_t *)base; @@ -693,13 +694,13 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, * * - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff * - set up PCI0 MEM0 at 0x10000000, size 0x8000000 - * - set up PCI0 MEM1 at 0x18200000, size 0xbe00000 * */ stw_p(p++, 0xe040); stw_p(p++, 0x0681); /* lui t1, %hi(0xb4000000) */ #if TARGET_BIG_ENDIAN +#define cpu_to_gt32 cpu_to_le32 stw_p(p++, 0xe020); stw_p(p++, 0x0be1); /* lui t0, %hi(0xdf000000) */ @@ -742,14 +743,8 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0xe020); stw_p(p++, 0x0821); /* lui t0, %hi(0xc1000000) */ - /* 0x80 corresponds to GT_PCI0M1LD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9080); - /* sw t0, 0x80(t1) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x0bc0); - /* lui t0, %hi(0x5e000000) */ - #else +#define cpu_to_gt32 cpu_to_be32 stw_p(p++, 0x0020); stw_p(p++, 0x00df); /* addiu[32] t0, $0, 0xdf */ @@ -792,19 +787,20 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0x0020); stw_p(p++, 0x00c1); /* addiu[32] t0, $0, 0xc1 */ - - /* 0x80 corresponds to GT_PCI0M1LD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9080); - /* sw t0, 0x80(t1) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x005e); - /* addiu[32] t0, $0, 0x5e */ - #endif + v = p; - /* 0x88 corresponds to GT_PCI0M1HD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9088); - /* sw t0, 0x88(t1) */ + /* setup PCI0 mem windows */ + bl_gen_write_u32(&v, /* GT_PCI0M1LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), + cpu_to_gt32(0x18200000 << 3)); + bl_gen_write_u32(&v, /* GT_PCI0M1HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), + cpu_to_gt32(0x0bc00000 << 3)); + + p = v; + +#undef cpu_to_gt32 stw_p(p++, 0xe320 | NM_HI1(kernel_entry)); From 262502a681e3e7efc54feb93a660a768c68e3395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:49:13 +0100 Subject: [PATCH 019/814] hw/mips/malta: Use bootloader generator API for nanoMIPS CPUs (2/5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 2/5: Convert PCI0 MEM0 BAR setup Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-8-philmd@linaro.org> --- hw/mips/malta.c | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index a496053a9a..7d0fc5d0c8 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -693,7 +693,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, * Load BAR registers as done by YAMON: * * - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff - * - set up PCI0 MEM0 at 0x10000000, size 0x8000000 * */ stw_p(p++, 0xe040); stw_p(p++, 0x0681); @@ -729,20 +728,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0xe020); stw_p(p++, 0x0001); /* lui t0, %hi(0x80000000) */ - /* 0x58 corresponds to GT_PCI0M0LD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9058); - /* sw t0, 0x58(t1) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x07e0); - /* lui t0, %hi(0x3f000000) */ - - /* 0x60 corresponds to GT_PCI0M0HD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9060); - /* sw t0, 0x60(t1) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x0821); - /* lui t0, %hi(0xc1000000) */ - #else #define cpu_to_gt32 cpu_to_be32 @@ -773,24 +758,16 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0x0020); stw_p(p++, 0x0080); /* addiu[32] t0, $0, 0x80 */ - - /* 0x58 corresponds to GT_PCI0M0LD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9058); - /* sw t0, 0x58(t1) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x003f); - /* addiu[32] t0, $0, 0x3f */ - - /* 0x60 corresponds to GT_PCI0M0HD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9060); - /* sw t0, 0x60(t1) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x00c1); - /* addiu[32] t0, $0, 0xc1 */ #endif v = p; /* setup PCI0 mem windows */ + bl_gen_write_u32(&v, /* GT_PCI0M0LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), + cpu_to_gt32(0x10000000 << 3)); + bl_gen_write_u32(&v, /* GT_PCI0M0HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), + cpu_to_gt32(0x07e00000 << 3)); bl_gen_write_u32(&v, /* GT_PCI0M1LD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), cpu_to_gt32(0x18200000 << 3)); From 02e0bec464ff3086446d4ad938e301bd85e57d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:54:49 +0100 Subject: [PATCH 020/814] hw/mips/malta: Use bootloader generator API for nanoMIPS CPUs (3/5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 3/5: Convert PCI0 I/O BAR setup Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-9-philmd@linaro.org> --- hw/mips/malta.c | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 7d0fc5d0c8..f0ed32167f 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -691,9 +691,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, /* * Load BAR registers as done by YAMON: - * - * - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff - * */ stw_p(p++, 0xe040); stw_p(p++, 0x0681); /* lui t1, %hi(0xb4000000) */ @@ -713,21 +710,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0xe020); stw_p(p++, 0x0801); /* lui t0, %hi(0xc0000000) */ - - /* 0x48 corresponds to GT_PCI0IOLD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9048); - /* sw t0, 0x48(t1) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x0800); - /* lui t0, %hi(0x40000000) */ - - /* 0x50 corresponds to GT_PCI0IOHD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9050); - /* sw t0, 0x50(t1) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x0001); - /* lui t0, %hi(0x80000000) */ - #else #define cpu_to_gt32 cpu_to_be32 @@ -744,23 +726,17 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0x0020); stw_p(p++, 0x00c0); /* addiu[32] t0, $0, 0xc0 */ - - /* 0x48 corresponds to GT_PCI0IOLD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9048); - /* sw t0, 0x48(t1) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x0040); - /* addiu[32] t0, $0, 0x40 */ - - /* 0x50 corresponds to GT_PCI0IOHD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9050); - /* sw t0, 0x50(t1) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x0080); - /* addiu[32] t0, $0, 0x80 */ #endif v = p; + /* setup PCI0 io window to 0x18000000-0x181fffff */ + bl_gen_write_u32(&v, /* GT_PCI0IOLD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), + cpu_to_gt32(0x18000000 << 3)); + bl_gen_write_u32(&v, /* GT_PCI0IOHD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), + cpu_to_gt32(0x08000000 << 3)); + /* setup PCI0 mem windows */ bl_gen_write_u32(&v, /* GT_PCI0M0LD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), From 3265f41fc7d988276c672e4bdc46ae60713f141c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 18:47:21 +0100 Subject: [PATCH 021/814] hw/mips/malta: Use bootloader generator API for nanoMIPS CPUs (4/5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 4/5: Convert GT64120 ISD base address setup Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-10-philmd@linaro.org> --- hw/mips/malta.c | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index f0ed32167f..e618513e35 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -689,46 +689,20 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, stw_p(p++, 0x80e7); stw_p(p++, NM_LO(loaderparams.ram_low_size)); /* ori a3,a3,%lo(loaderparams.ram_low_size) */ - /* - * Load BAR registers as done by YAMON: - */ - stw_p(p++, 0xe040); stw_p(p++, 0x0681); - /* lui t1, %hi(0xb4000000) */ - #if TARGET_BIG_ENDIAN #define cpu_to_gt32 cpu_to_le32 - - stw_p(p++, 0xe020); stw_p(p++, 0x0be1); - /* lui t0, %hi(0xdf000000) */ - - /* 0x68 corresponds to GT_ISD (from hw/mips/gt64xxx_pci.c) */ - stw_p(p++, 0x8422); stw_p(p++, 0x9068); - /* sw t0, 0x68(t1) */ - - stw_p(p++, 0xe040); stw_p(p++, 0x077d); - /* lui t1, %hi(0xbbe00000) */ - - stw_p(p++, 0xe020); stw_p(p++, 0x0801); - /* lui t0, %hi(0xc0000000) */ #else #define cpu_to_gt32 cpu_to_be32 - - stw_p(p++, 0x0020); stw_p(p++, 0x00df); - /* addiu[32] t0, $0, 0xdf */ - - /* 0x68 corresponds to GT_ISD */ - stw_p(p++, 0x8422); stw_p(p++, 0x9068); - /* sw t0, 0x68(t1) */ - - /* Use kseg2 remapped address 0x1be00000 */ - stw_p(p++, 0xe040); stw_p(p++, 0x077d); - /* lui t1, %hi(0xbbe00000) */ - - stw_p(p++, 0x0020); stw_p(p++, 0x00c0); - /* addiu[32] t0, $0, 0xc0 */ #endif v = p; + /* setup MEM-to-PCI0 mapping as done by YAMON */ + + /* move GT64120 registers from 0x14000000 to 0x1be00000 */ + bl_gen_write_u32(&v, /* GT_ISD */ + cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), + cpu_to_gt32(0x1be00000 << 3)); + /* setup PCI0 io window to 0x18000000-0x181fffff */ bl_gen_write_u32(&v, /* GT_PCI0IOLD */ cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), From 9f911a25277aceaad14dc1ce4ac330ad5b057d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 19:08:50 +0100 Subject: [PATCH 022/814] hw/mips/malta: Use bootloader generator API for nanoMIPS CPUs (5/5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part 5/5: Convert jumping to kernel Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-11-philmd@linaro.org> --- hw/mips/malta.c | 68 ++++++++----------------------------------------- 1 file changed, 11 insertions(+), 57 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index e618513e35..b66dad0510 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -625,11 +625,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, /* Small bootloader */ p = (uint16_t *)base; -#define NM_HI1(VAL) (((VAL) >> 16) & 0x1f) -#define NM_HI2(VAL) \ - (((VAL) & 0xf000) | (((VAL) >> 19) & 0xffc) | (((VAL) >> 31) & 0x1)) -#define NM_LO(VAL) ((VAL) & 0xfff) - stw_p(p++, 0x2800); stw_p(p++, 0x001c); /* bc to_here */ stw_p(p++, 0x8000); stw_p(p++, 0xc000); @@ -648,46 +643,6 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, /* nop */ /* to_here: */ - if (semihosting_get_argc()) { - /* Preserve a0 content as arguments have been passed */ - stw_p(p++, 0x8000); stw_p(p++, 0xc000); - /* nop */ - } else { - stw_p(p++, 0x0080); stw_p(p++, 0x0002); - /* li a0,2 */ - } - - stw_p(p++, 0xe3a0 | NM_HI1(ENVP_VADDR - 64)); - - stw_p(p++, NM_HI2(ENVP_VADDR - 64)); - /* lui sp,%hi(ENVP_VADDR - 64) */ - - stw_p(p++, 0x83bd); stw_p(p++, NM_LO(ENVP_VADDR - 64)); - /* ori sp,sp,%lo(ENVP_VADDR - 64) */ - - stw_p(p++, 0xe0a0 | NM_HI1(ENVP_VADDR)); - - stw_p(p++, NM_HI2(ENVP_VADDR)); - /* lui a1,%hi(ENVP_VADDR) */ - - stw_p(p++, 0x80a5); stw_p(p++, NM_LO(ENVP_VADDR)); - /* ori a1,a1,%lo(ENVP_VADDR) */ - - stw_p(p++, 0xe0c0 | NM_HI1(ENVP_VADDR + 8)); - - stw_p(p++, NM_HI2(ENVP_VADDR + 8)); - /* lui a2,%hi(ENVP_VADDR + 8) */ - - stw_p(p++, 0x80c6); stw_p(p++, NM_LO(ENVP_VADDR + 8)); - /* ori a2,a2,%lo(ENVP_VADDR + 8) */ - - stw_p(p++, 0xe0e0 | NM_HI1(loaderparams.ram_low_size)); - - stw_p(p++, NM_HI2(loaderparams.ram_low_size)); - /* lui a3,%hi(loaderparams.ram_low_size) */ - - stw_p(p++, 0x80e7); stw_p(p++, NM_LO(loaderparams.ram_low_size)); - /* ori a3,a3,%lo(loaderparams.ram_low_size) */ #if TARGET_BIG_ENDIAN #define cpu_to_gt32 cpu_to_le32 @@ -725,20 +680,19 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), cpu_to_gt32(0x0bc00000 << 3)); - p = v; - #undef cpu_to_gt32 - stw_p(p++, 0xe320 | NM_HI1(kernel_entry)); - - stw_p(p++, NM_HI2(kernel_entry)); - /* lui t9,%hi(kernel_entry) */ - - stw_p(p++, 0x8339); stw_p(p++, NM_LO(kernel_entry)); - /* ori t9,t9,%lo(kernel_entry) */ - - stw_p(p++, 0x4bf9); stw_p(p++, 0x0000); - /* jalrc t8 */ + bl_gen_jump_kernel(&v, + true, ENVP_VADDR - 64, + /* + * If semihosting is used, arguments have already been + * passed, so we preserve $a0. + */ + !semihosting_get_argc(), 2, + true, ENVP_VADDR, + true, ENVP_VADDR + 8, + true, loaderparams.ram_low_size, + kernel_entry); } /* From 0e45355c5cf0f4ec88b5484c3bf2574bdc9c4e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 11 Dec 2022 21:25:48 +0100 Subject: [PATCH 023/814] hw/mips/malta: Merge common BL code as bl_setup_gt64120_jump_kernel() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge common code shared between write_bootloader() and write_bootloader_nanomips() into bl_setup_gt64120_jump_kernel(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221211204533.85359-12-philmd@linaro.org> --- hw/mips/malta.c | 155 +++++++++++++++++------------------------------- 1 file changed, 56 insertions(+), 99 deletions(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index b66dad0510..34c24110cd 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -616,11 +616,64 @@ static void network_init(PCIBus *pci_bus) } } +static void bl_setup_gt64120_jump_kernel(void **p, uint64_t run_addr, + uint64_t kernel_entry) +{ + /* Bus endianess is always reversed */ +#if TARGET_BIG_ENDIAN +#define cpu_to_gt32 cpu_to_le32 +#else +#define cpu_to_gt32 cpu_to_be32 +#endif + + /* setup MEM-to-PCI0 mapping as done by YAMON */ + + /* move GT64120 registers from 0x14000000 to 0x1be00000 */ + bl_gen_write_u32(p, /* GT_ISD */ + cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), + cpu_to_gt32(0x1be00000 << 3)); + + /* setup PCI0 io window to 0x18000000-0x181fffff */ + bl_gen_write_u32(p, /* GT_PCI0IOLD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), + cpu_to_gt32(0x18000000 << 3)); + bl_gen_write_u32(p, /* GT_PCI0IOHD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), + cpu_to_gt32(0x08000000 << 3)); + + /* setup PCI0 mem windows */ + bl_gen_write_u32(p, /* GT_PCI0M0LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), + cpu_to_gt32(0x10000000 << 3)); + bl_gen_write_u32(p, /* GT_PCI0M0HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), + cpu_to_gt32(0x07e00000 << 3)); + bl_gen_write_u32(p, /* GT_PCI0M1LD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), + cpu_to_gt32(0x18200000 << 3)); + bl_gen_write_u32(p, /* GT_PCI0M1HD */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), + cpu_to_gt32(0x0bc00000 << 3)); + +#undef cpu_to_gt32 + + bl_gen_jump_kernel(p, + true, ENVP_VADDR - 64, + /* + * If semihosting is used, arguments have already + * been passed, so we preserve $a0. + */ + !semihosting_get_argc(), 2, + true, ENVP_VADDR, + true, ENVP_VADDR + 8, + true, loaderparams.ram_low_size, + kernel_entry); +} + static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, uint64_t kernel_entry) { uint16_t *p; - void *v; /* Small bootloader */ p = (uint16_t *)base; @@ -644,55 +697,7 @@ static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr, /* to_here: */ -#if TARGET_BIG_ENDIAN -#define cpu_to_gt32 cpu_to_le32 -#else -#define cpu_to_gt32 cpu_to_be32 -#endif - v = p; - - /* setup MEM-to-PCI0 mapping as done by YAMON */ - - /* move GT64120 registers from 0x14000000 to 0x1be00000 */ - bl_gen_write_u32(&v, /* GT_ISD */ - cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), - cpu_to_gt32(0x1be00000 << 3)); - - /* setup PCI0 io window to 0x18000000-0x181fffff */ - bl_gen_write_u32(&v, /* GT_PCI0IOLD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), - cpu_to_gt32(0x18000000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0IOHD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), - cpu_to_gt32(0x08000000 << 3)); - - /* setup PCI0 mem windows */ - bl_gen_write_u32(&v, /* GT_PCI0M0LD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), - cpu_to_gt32(0x10000000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0M0HD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), - cpu_to_gt32(0x07e00000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0M1LD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), - cpu_to_gt32(0x18200000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0M1HD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), - cpu_to_gt32(0x0bc00000 << 3)); - -#undef cpu_to_gt32 - - bl_gen_jump_kernel(&v, - true, ENVP_VADDR - 64, - /* - * If semihosting is used, arguments have already been - * passed, so we preserve $a0. - */ - !semihosting_get_argc(), 2, - true, ENVP_VADDR, - true, ENVP_VADDR + 8, - true, loaderparams.ram_low_size, - kernel_entry); + bl_setup_gt64120_jump_kernel((void **)&p, run_addr, kernel_entry); } /* @@ -758,55 +763,8 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, * */ - /* Bus endianess is always reversed */ -#if TARGET_BIG_ENDIAN -#define cpu_to_gt32 cpu_to_le32 -#else -#define cpu_to_gt32 cpu_to_be32 -#endif v = p; - - /* move GT64120 registers from 0x14000000 to 0x1be00000 */ - bl_gen_write_u32(&v, /* GT_ISD */ - cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68), - cpu_to_gt32(0x1be00000 << 3)); - - /* setup MEM-to-PCI0 mapping */ - /* setup PCI0 io window to 0x18000000-0x181fffff */ - bl_gen_write_u32(&v, /* GT_PCI0IOLD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48), - cpu_to_gt32(0x18000000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0IOHD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50), - cpu_to_gt32(0x08000000 << 3)); - /* setup PCI0 mem windows */ - bl_gen_write_u32(&v, /* GT_PCI0M0LD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58), - cpu_to_gt32(0x10000000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0M0HD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60), - cpu_to_gt32(0x07e00000 << 3)); - - bl_gen_write_u32(&v, /* GT_PCI0M1LD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80), - cpu_to_gt32(0x18200000 << 3)); - bl_gen_write_u32(&v, /* GT_PCI0M1HD */ - cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88), - cpu_to_gt32(0x0bc00000 << 3)); - -#undef cpu_to_gt32 - - bl_gen_jump_kernel(&v, - true, ENVP_VADDR - 64, - /* - * If semihosting is used, arguments have already been - * passed, so we preserve $a0. - */ - !semihosting_get_argc(), 2, - true, ENVP_VADDR, - true, ENVP_VADDR + 8, - true, loaderparams.ram_low_size, - kernel_entry); + bl_setup_gt64120_jump_kernel(&v, run_addr, kernel_entry); p = v; /* YAMON subroutines */ @@ -851,7 +809,6 @@ static void write_bootloader(uint8_t *base, uint64_t run_addr, stl_p(p++, 0x00000000); /* nop */ stl_p(p++, 0x03e00009); /* jalr ra */ stl_p(p++, 0xa1040000); /* sb a0,0(t0) */ - } static void G_GNUC_PRINTF(3, 4) prom_set(uint32_t *prom_buf, int index, From 6dd92ce6c541d331f384b808173b7c97c09c8684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Oct 2022 01:53:53 +0200 Subject: [PATCH 024/814] hw/mips/malta: Introduce PIIX4_PCI_DEVFN definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PIIX4 PCI-ISA bridge function is always located at 10:0. Since we want to re-use its address, add the PIIX4_PCI_DEVFN definition. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Message-Id: <20221027204720.33611-2-philmd@linaro.org> --- hw/mips/malta.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 34c24110cd..9fc3280407 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -71,6 +71,8 @@ #define FLASH_SIZE 0x400000 +#define PIIX4_PCI_DEVFN PCI_DEVFN(10, 0) + typedef struct { MemoryRegion iomem; MemoryRegion iomem_lo; /* 0 - 0x900 */ @@ -1239,7 +1241,7 @@ void mips_malta_init(MachineState *machine) pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); /* Southbridge */ - piix4 = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), true, + piix4 = pci_create_simple_multifunction(pci_bus, PIIX4_PCI_DEVFN, true, TYPE_PIIX4_PCI_DEVICE); isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0")); From 1953dfa80e0fc44a8ccfc97b4ada941e9383bba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Oct 2022 01:54:46 +0200 Subject: [PATCH 025/814] hw/mips/malta: Set PIIX4 IRQ routes in embedded bootloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linux kernel expects the northbridge & southbridge chipsets configured by the BIOS firmware. We emulate that by writing a tiny bootloader code in write_bootloader(). Upon introduction in commit 5c2b87e34d ("PIIX4 support"), the PIIX4 configuration space included values specific to the Malta board. Set the Malta-specific IRQ routing values in the embedded bootloader, so the next commit can remove the Malta specific bits from the PIIX4 PCI-ISA bridge and make it generic (matching the real hardware). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20221027204720.33611-3-philmd@linaro.org> --- hw/mips/malta.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 9fc3280407..ae76b4db70 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -621,6 +621,10 @@ static void network_init(PCIBus *pci_bus) static void bl_setup_gt64120_jump_kernel(void **p, uint64_t run_addr, uint64_t kernel_entry) { + static const char pci_pins_cfg[PCI_NUM_PINS] = { + 10, 10, 11, 11 /* PIIX IRQRC[A:D] */ + }; + /* Bus endianess is always reversed */ #if TARGET_BIG_ENDIAN #define cpu_to_gt32 cpu_to_le32 @@ -659,6 +663,20 @@ static void bl_setup_gt64120_jump_kernel(void **p, uint64_t run_addr, #undef cpu_to_gt32 + /* + * The PIIX ISA bridge is on PCI bus 0 dev 10 func 0. + * Load the PIIX IRQC[A:D] routing config address, then + * write routing configuration to the config data register. + */ + bl_gen_write_u32(p, /* GT_PCI0_CFGADDR */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0xcf8), + tswap32((1 << 31) /* ConfigEn */ + | PCI_BUILD_BDF(0, PIIX4_PCI_DEVFN) << 8 + | PIIX_PIRQCA)); + bl_gen_write_u32(p, /* GT_PCI0_CFGDATA */ + cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0xcfc), + tswap32(ldl_be_p(pci_pins_cfg))); + bl_gen_jump_kernel(p, true, ENVP_VADDR - 64, /* From c12b1e67d50c01f6ba78abcdaaa533abaf71b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Oct 2022 21:06:36 +0200 Subject: [PATCH 026/814] hw/isa/piix4: Correct IRQRC[A:D] reset values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IRQRC[A:D] registers reset value is 0x80. We were forcing the MIPS Malta machine routing to be able to boot a Linux kernel without any bootloader. We now have these registers initialized in the Malta machine write_bootloader(), so we can use the correct reset values. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Message-Id: <20221027204720.33611-4-philmd@linaro.org> --- hw/isa/piix4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 8fc1db6dc9..0d23e11a39 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -116,10 +116,10 @@ static void piix4_isa_reset(DeviceState *dev) pci_conf[0x4c] = 0x4d; pci_conf[0x4e] = 0x03; pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10 - pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10 - pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11 - pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11 + pci_conf[0x60] = 0x80; + pci_conf[0x61] = 0x80; + pci_conf[0x62] = 0x80; + pci_conf[0x63] = 0x80; pci_conf[0x69] = 0x02; pci_conf[0x70] = 0x80; pci_conf[0x76] = 0x0c; From a844873512400fae6bed9e87694dc96ff2f15f39 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 18 Dec 2022 01:06:45 +0100 Subject: [PATCH 027/814] mips: Remove support for trap and emulate KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This support was limited to the Malta board, drop it. I do not have a machine that can run VZ KVM, so I am assuming that it works for -M malta as well. Signed-off-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221221091718.71844-1-philmd@linaro.org> --- docs/about/deprecated.rst | 9 ------- docs/about/removed-features.rst | 9 +++++++ hw/mips/malta.c | 46 +++++---------------------------- target/mips/cpu.c | 7 +---- target/mips/cpu.h | 3 --- target/mips/internal.h | 3 --- target/mips/kvm.c | 11 +------- target/mips/sysemu/addr.c | 17 ------------ target/mips/sysemu/physaddr.c | 13 ---------- 9 files changed, 18 insertions(+), 100 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 68d29642d7..9f1bbc495d 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -171,15 +171,6 @@ 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. -System accelerators -------------------- - -MIPS ``Trap-and-Emul`` KVM support (since 6.0) -'''''''''''''''''''''''''''''''''''''''''''''' - -The MIPS ``Trap-and-Emul`` KVM host and guest support has been removed -from Linux upstream kernel, declare it deprecated. - Host Architectures ------------------ diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index c918cabd1a..6c3aa5097f 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -652,6 +652,15 @@ Userspace local APIC with KVM (x86, removed 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. +System accelerators +------------------- + +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. + System emulator machines ------------------------ diff --git a/hw/mips/malta.c b/hw/mips/malta.c index ae76b4db70..8bf2e2ff5f 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -57,6 +57,7 @@ #include "semihosting/semihost.h" #include "hw/mips/cps.h" #include "hw/qdev-clock.h" +#include "target/mips/internal.h" #include "trace.h" #define ENVP_PADDR 0x2000 @@ -875,7 +876,6 @@ static uint64_t load_kernel(void) uint32_t *prom_buf; long prom_size; int prom_index = 0; - uint64_t (*xlate_to_kseg0) (void *opaque, uint64_t addr); uint8_t rng_seed[32]; char rng_seed_hex[sizeof(rng_seed) * 2 + 1]; size_t rng_seed_prom_offset; @@ -899,19 +899,10 @@ static uint64_t load_kernel(void) } /* Check where the kernel has been linked */ - if (kernel_entry & 0x80000000ll) { - if (kvm_enabled()) { - error_report("KVM guest kernels must be linked in useg. " - "Did you forget to enable CONFIG_KVM_GUEST?"); - exit(1); - } - - xlate_to_kseg0 = cpu_mips_phys_to_kseg0; - } else { - /* if kernel entry is in useg it is probably a KVM T&E kernel */ - mips_um_ksegs_enable(); - - xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0; + if (kernel_entry <= USEG_LIMIT) { + error_report("Trap-and-Emul kernels (Linux CONFIG_KVM_GUEST)" + " are not supported"); + exit(1); } /* load initrd */ @@ -952,7 +943,7 @@ static uint64_t load_kernel(void) if (initrd_size > 0) { prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s", - xlate_to_kseg0(NULL, initrd_offset), + cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline); @@ -1019,11 +1010,6 @@ static void main_cpu_reset(void *opaque) } malta_mips_config(cpu); - - if (kvm_enabled()) { - /* Start running from the bootloader we wrote to end of RAM */ - env->active_tc.PC = 0x40000000 + loaderparams.ram_low_size; - } } static void create_cpu_without_cps(MachineState *ms, MaltaState *s, @@ -1157,13 +1143,7 @@ void mips_malta_init(MachineState *machine) fl_idx++; if (kernel_filename) { ram_low_size = MIN(ram_size, 256 * MiB); - /* For KVM we reserve 1MB of RAM for running bootloader */ - if (kvm_enabled()) { - ram_low_size -= 0x100000; - bootloader_run_addr = cpu_mips_kvm_um_phys_to_kseg0(NULL, ram_low_size); - } else { - bootloader_run_addr = cpu_mips_phys_to_kseg0(NULL, RESET_ADDRESS); - } + bootloader_run_addr = cpu_mips_phys_to_kseg0(NULL, RESET_ADDRESS); /* Write a small bootloader to the flash location. */ loaderparams.ram_size = ram_size; @@ -1180,20 +1160,8 @@ void mips_malta_init(MachineState *machine) write_bootloader_nanomips(memory_region_get_ram_ptr(bios), bootloader_run_addr, kernel_entry); } - if (kvm_enabled()) { - /* Write the bootloader code @ the end of RAM, 1MB reserved */ - write_bootloader(memory_region_get_ram_ptr(ram_low_preio) + - ram_low_size, - bootloader_run_addr, kernel_entry); - } } else { target_long bios_size = FLASH_SIZE; - /* The flash region isn't executable from a KVM guest */ - if (kvm_enabled()) { - error_report("KVM enabled but no -kernel argument was specified. " - "Booting from flash is not supported with KVM."); - exit(1); - } /* Load firmware from flash. */ if (!dinfo) { /* Load a BIOS image. */ diff --git a/target/mips/cpu.c b/target/mips/cpu.c index c614b04607..052e54bda3 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -292,12 +292,7 @@ static void mips_cpu_reset_hold(Object *obj) env->tlb->tlb_in_use = env->tlb->nb_tlb; env->CP0_Wired = 0; env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId; - env->CP0_EBase = (cs->cpu_index & 0x3FF); - if (mips_um_ksegs_enabled()) { - env->CP0_EBase |= 0x40000000; - } else { - env->CP0_EBase |= (int32_t)0x80000000; - } + env->CP0_EBase = KSEG0_BASE | (cs->cpu_index & 0x3FF); if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) { env->CP0_CMGCRBase = 0x1fbf8000 >> 4; } diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 0a085643a3..caf2b06911 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1296,11 +1296,8 @@ void cpu_set_exception_base(int vp_index, target_ulong address); uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr); uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr); -uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr); uint64_t cpu_mips_kseg1_to_phys(void *opaque, uint64_t addr); uint64_t cpu_mips_phys_to_kseg1(void *opaque, uint64_t addr); -bool mips_um_ksegs_enabled(void); -void mips_um_ksegs_enable(void); #if !defined(CONFIG_USER_ONLY) diff --git a/target/mips/internal.h b/target/mips/internal.h index 57b312689a..4b0031d10d 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -99,9 +99,6 @@ int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL) #define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL) -#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL) -#define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL) - #if !defined(CONFIG_USER_ONLY) enum { diff --git a/target/mips/kvm.c b/target/mips/kvm.c index bcb8e06b2c..c14e8f550f 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -1268,25 +1268,16 @@ int kvm_arch_msi_data_to_gsi(uint32_t data) int mips_kvm_type(MachineState *machine, const char *vm_type) { -#if defined(KVM_CAP_MIPS_VZ) || defined(KVM_CAP_MIPS_TE) +#if defined(KVM_CAP_MIPS_VZ) int r; KVMState *s = KVM_STATE(machine->accelerator); -#endif -#if defined(KVM_CAP_MIPS_VZ) r = kvm_check_extension(s, KVM_CAP_MIPS_VZ); if (r > 0) { return KVM_VM_MIPS_VZ; } #endif -#if defined(KVM_CAP_MIPS_TE) - r = kvm_check_extension(s, KVM_CAP_MIPS_TE); - if (r > 0) { - return KVM_VM_MIPS_TE; - } -#endif - return -1; } diff --git a/target/mips/sysemu/addr.c b/target/mips/sysemu/addr.c index 86f1c129c9..4f025be44a 100644 --- a/target/mips/sysemu/addr.c +++ b/target/mips/sysemu/addr.c @@ -23,8 +23,6 @@ #include "qemu/osdep.h" #include "cpu.h" -static int mips_um_ksegs; - uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) { return addr & 0x1fffffffll; @@ -35,11 +33,6 @@ uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr) return addr | ~0x7fffffffll; } -uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr) -{ - return addr | 0x40000000ll; -} - uint64_t cpu_mips_kseg1_to_phys(void *opaque, uint64_t addr) { return addr & 0x1fffffffll; @@ -49,13 +42,3 @@ uint64_t cpu_mips_phys_to_kseg1(void *opaque, uint64_t addr) { return (addr & 0x1fffffffll) | 0xffffffffa0000000ll; } - -bool mips_um_ksegs_enabled(void) -{ - return mips_um_ksegs; -} - -void mips_um_ksegs_enable(void) -{ - mips_um_ksegs = 1; -} diff --git a/target/mips/sysemu/physaddr.c b/target/mips/sysemu/physaddr.c index 1918633aa1..2970df8a09 100644 --- a/target/mips/sysemu/physaddr.c +++ b/target/mips/sysemu/physaddr.c @@ -130,19 +130,6 @@ int get_physical_address(CPUMIPSState *env, hwaddr *physical, /* effective address (modified for KVM T&E kernel segments) */ target_ulong address = real_address; - if (mips_um_ksegs_enabled()) { - /* KVM T&E adds guest kernel segments in useg */ - if (real_address >= KVM_KSEG0_BASE) { - if (real_address < KVM_KSEG2_BASE) { - /* kseg0 */ - address += KSEG0_BASE - KVM_KSEG0_BASE; - } else if (real_address <= USEG_LIMIT) { - /* kseg2/3 */ - address += KSEG2_BASE - KVM_KSEG2_BASE; - } - } - } - if (address <= USEG_LIMIT) { /* useg */ uint16_t segctl; From f9950374300cb4d8d898bbfc694a0639e9aafdc3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jan 2023 09:49:42 +0100 Subject: [PATCH 028/814] mips: Always include nanomips disassembler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the nanomips disassembler is not C++ code anymore, it need not depend on link_language == cpp. Always include it and remove the CONFIG_NANOMIPS_DIS symbol. Cc: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20230110084942.299460-1-pbonzini@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- disas/meson.build | 3 +-- include/exec/poison.h | 1 - meson.build | 5 ----- target/mips/cpu.c | 2 -- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/disas/meson.build b/disas/meson.build index 1977f5cd92..c865bdd882 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -4,8 +4,7 @@ common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) -common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) -common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.c')) +common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c', 'nanomips.c')) common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files('riscv.c')) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) diff --git a/include/exec/poison.h b/include/exec/poison.h index f0959bc84e..140daa4a85 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -74,7 +74,6 @@ #pragma GCC poison CONFIG_M68K_DIS #pragma GCC poison CONFIG_MICROBLAZE_DIS #pragma GCC poison CONFIG_MIPS_DIS -#pragma GCC poison CONFIG_NANOMIPS_DIS #pragma GCC poison CONFIG_NIOS2_DIS #pragma GCC poison CONFIG_PPC_DIS #pragma GCC poison CONFIG_RISCV_DIS diff --git a/meson.build b/meson.build index 175517eafd..5d68a8fd23 100644 --- a/meson.build +++ b/meson.build @@ -2490,11 +2490,6 @@ disassemblers = { 'xtensa' : ['CONFIG_XTENSA_DIS'], 'loongarch' : ['CONFIG_LOONGARCH_DIS'], } -if link_language == 'cpp' - disassemblers += { - 'mips' : [ 'CONFIG_MIPS_DIS', 'CONFIG_NANOMIPS_DIS'], - } -endif have_ivshmem = config_host_data.get('CONFIG_EVENTFD') host_kconfig = \ diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 052e54bda3..f995e88776 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -434,9 +434,7 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) info->print_insn = print_insn_little_mips; #endif } else { -#if defined(CONFIG_NANOMIPS_DIS) info->print_insn = print_insn_nanomips; -#endif } } From 1bdad09bf3326b89add221ef092e57ed81f6e347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 4 Jan 2023 12:13:00 +0100 Subject: [PATCH 029/814] hw/pci/pci_host: Trace config accesses on unexisting functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only emit trace events for existing PCI functions. In order to ease debugging PCI enumeration process, also emit for unexisting functions: $ qemu-system-foo -trace pci_cfg_\* ... pci_cfg_read empty 00:0a.4 @0x0 -> 0xffffffff pci_cfg_read empty 00:0a.5 @0x0 -> 0xffffffff pci_cfg_read empty 00:0a.6 @0x0 -> 0xffffffff pci_cfg_read empty 00:0a.7 @0x0 -> 0xffffffff pci_cfg_read pcnet 00:0b.0 @0x0 -> 0x20001022 pci_cfg_read empty 00:0c.0 @0x0 -> 0xffffffff pci_cfg_read empty 00:0d.0 @0x0 -> 0xffffffff pci_cfg_read empty 00:0e.0 @0x0 -> 0xffffffff pci_cfg_read empty 00:0f.0 @0x0 -> 0xffffffff pci_cfg_read empty 00:10.0 @0x0 -> 0xffffffff pci_cfg_read empty 00:11.0 @0x0 -> 0xffffffff pci_cfg_read cirrus-vga 00:12.0 @0x0 -> 0xb81013 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230104133935.4639-2-philmd@linaro.org> --- hw/pci/pci_host.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index eaf217ff55..ead1d3e61c 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -118,6 +118,9 @@ void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, unsigned len) uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); if (!pci_dev) { + trace_pci_cfg_write("empty", extract32(addr, 16, 8), + extract32(addr, 11, 5), extract32(addr, 8, 3), + config_addr, val); return; } @@ -131,6 +134,9 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len) uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1); if (!pci_dev) { + trace_pci_cfg_read("empty", extract32(addr, 16, 8), + extract32(addr, 11, 5), extract32(addr, 8, 3), + config_addr, ~0x0); return ~0x0; } From f021f4e9d269746bc89dadf0cac117154733e4be Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:17 +0100 Subject: [PATCH 030/814] hw/pci/pci: Factor out pci_bus_map_irqs() from pci_bus_irqs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_bus_irqs() coupled together the assignment of pci_set_irq_fn and pci_map_irq_fn to a PCI bus. This coupling gets in the way when the pci_map_irq_fn is board-specific while the pci_set_irq_fn is device- specific. For example, both of QEMU's PIIX south bridge models have different pci_map_irq_fn implementations which are board-specific rather than device-specific. These implementations should therefore reside in board code. The pci_set_irq_fn's, however, should stay in the device models because they access memory internal to the model. Factoring out pci_bus_map_irqs() from pci_bus_irqs() allows the assignments to be decoupled, resolving the problem described above. Note also how pci_vpb_realize() which gets touched in this commit assigns different pci_map_irq_fn's depending on the board. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109172347.1830-5-shentey@gmail.com> [PMD: Factor out in vfu_object_set_bus_irq()] Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_q35.c | 4 ++-- hw/isa/piix3.c | 8 ++++---- hw/isa/piix4.c | 3 ++- hw/pci-host/raven.c | 3 ++- hw/pci-host/versatile.c | 3 ++- hw/pci/pci.c | 12 +++++++++--- hw/remote/machine.c | 3 ++- hw/remote/vfio-user-obj.c | 4 ++-- include/hw/pci/pci.h | 3 ++- 9 files changed, 27 insertions(+), 16 deletions(-) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 67ceb04bcc..65ea226211 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -268,8 +268,8 @@ static void pc_q35_init(MachineState *machine) for (i = 0; i < GSI_NUM_PINS; i++) { qdev_connect_gpio_out_named(lpc_dev, ICH9_GPIO_GSI, i, x86ms->gsi[i]); } - pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, - ICH9_LPC_NB_PIRQS); + pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc, ICH9_LPC_NB_PIRQS); + pci_bus_map_irqs(host_bus, ich9_lpc_map_irq); pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); isa_bus = ich9_lpc->isa_bus; diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index eabad7ba58..666e794f77 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -384,8 +384,8 @@ static void piix3_realize(PCIDevice *dev, Error **errp) return; } - pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq, - piix3, PIIX_NUM_PIRQS); + pci_bus_irqs(pci_bus, piix3_set_irq, piix3, PIIX_NUM_PIRQS); + pci_bus_map_irqs(pci_bus, pci_slot_get_pirq); pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); } @@ -420,8 +420,8 @@ static void piix3_xen_realize(PCIDevice *dev, Error **errp) * connected to the IOAPIC directly. * These additional routes can be discovered through ACPI. */ - pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); + pci_bus_irqs(pci_bus, xen_piix3_set_irq, piix3, XEN_PIIX_NUM_PIRQS); + pci_bus_map_irqs(pci_bus, xen_pci_slot_get_pirq); } static void piix3_xen_class_init(ObjectClass *klass, void *data) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 0d23e11a39..9c79c9677b 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -271,7 +271,8 @@ static void piix4_realize(PCIDevice *dev, Error **errp) } qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa[9]); - pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS); + pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); + pci_bus_map_irqs(pci_bus, pci_slot_get_pirq); } static void piix4_init(Object *obj) diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index 2c96ddf8fe..5b00b4e462 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -258,7 +258,8 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) qdev_init_gpio_in(d, raven_change_gpio, 1); - pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s, PCI_NUM_PINS); + pci_bus_irqs(&s->pci_bus, raven_set_irq, s, PCI_NUM_PINS); + pci_bus_map_irqs(&s->pci_bus, raven_map_irq); memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s, "pci-conf-idx", 4); diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index 0d50ea4cc0..60d4e7cd92 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -422,7 +422,8 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) mapfn = pci_vpb_map_irq; } - pci_bus_irqs(&s->pci_bus, pci_vpb_set_irq, mapfn, s->irq, 4); + pci_bus_irqs(&s->pci_bus, pci_vpb_set_irq, s->irq, 4); + pci_bus_map_irqs(&s->pci_bus, mapfn); /* Our memory regions are: * 0 : our control registers diff --git a/hw/pci/pci.c b/hw/pci/pci.c index c2fb88f9a3..39a7bb32aa 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -280,6 +280,7 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) PCIBus *bus; for (;;) { bus = pci_get_bus(pci_dev); + assert(bus->map_irq); irq_num = bus->map_irq(pci_dev, irq_num); if (bus->set_irq) break; @@ -518,16 +519,20 @@ void pci_root_bus_cleanup(PCIBus *bus) qbus_unrealize(BUS(bus)); } -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, void *irq_opaque, int nirq) { bus->set_irq = set_irq; - bus->map_irq = map_irq; bus->irq_opaque = irq_opaque; bus->nirq = nirq; bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0])); } +void pci_bus_map_irqs(PCIBus *bus, pci_map_irq_fn map_irq) +{ + bus->map_irq = map_irq; +} + void pci_bus_irqs_cleanup(PCIBus *bus) { bus->set_irq = NULL; @@ -549,7 +554,8 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name, bus = pci_root_bus_new(parent, name, address_space_mem, address_space_io, devfn_min, typename); - pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); + pci_bus_irqs(bus, set_irq, irq_opaque, nirq); + pci_bus_map_irqs(bus, map_irq); return bus; } diff --git a/hw/remote/machine.c b/hw/remote/machine.c index 75d550daae..519f855ec1 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -63,8 +63,9 @@ static void remote_machine_init(MachineState *machine) } else { remote_iohub_init(&s->iohub); - pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq, + pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, &s->iohub, REMOTE_IOHUB_NB_PIRQS); + pci_bus_map_irqs(pci_host->bus, remote_iohub_map_irq); } qbus_set_hotplug_handler(BUS(pci_host->bus), OBJECT(s)); diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index fe1fdfb5f7..88ffafc73e 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -665,8 +665,8 @@ void vfu_object_set_bus_irq(PCIBus *pci_bus) int bus_num = pci_bus_num(pci_bus); int max_bdf = PCI_BUILD_BDF(bus_num, PCI_DEVFN_MAX - 1); - pci_bus_irqs(pci_bus, vfu_object_set_irq, vfu_object_map_irq, pci_bus, - max_bdf); + pci_bus_irqs(pci_bus, vfu_object_set_irq, pci_bus, max_bdf); + pci_bus_map_irqs(pci_bus, vfu_object_map_irq); } static int vfu_object_device_reset(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 7048a373d1..85ee458cd2 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -282,8 +282,9 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name, MemoryRegion *address_space_io, uint8_t devfn_min, const char *typename); void pci_root_bus_cleanup(PCIBus *bus); -void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, +void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, void *irq_opaque, int nirq); +void pci_bus_map_irqs(PCIBus *bus, pci_map_irq_fn map_irq); void pci_bus_irqs_cleanup(PCIBus *bus); int pci_bus_get_irq_level(PCIBus *bus, int irq_num); /* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ From 738c2eb47f2fb150a337b6bfb151f4339d0bb8b3 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:18 +0100 Subject: [PATCH 031/814] hw/isa/piix3: Decouple INTx-to-LNKx routing which is board-specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_map_irq_fn's in general seem to be board-specific. So move PIIX3's pci_slot_get_pirq() to board code to not have PIIX3 make assuptions about its board. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109172347.1830-6-shentey@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_piix.c | 15 +++++++++++++++ hw/isa/piix3.c | 13 ------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index b48047f50c..bb3b10557f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -47,6 +47,7 @@ #include "hw/sysbus.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/xen/xen-x86.h" +#include "hw/xen/xen.h" #include "exec/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/piix4.h" @@ -73,6 +74,17 @@ static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; #endif +/* + * Return the global irq number corresponding to a given device irq + * pin. We could also use the bus number to have a more precise mapping. + */ +static int pc_pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) +{ + int slot_addend; + slot_addend = PCI_SLOT(pci_dev->devfn) - 1; + return (pci_intx + slot_addend) & 3; +} + /* PC hardware initialisation */ static void pc_init1(MachineState *machine, const char *host_type, const char *pci_type) @@ -216,6 +228,9 @@ static void pc_init1(MachineState *machine, x86ms->below_4g_mem_size, x86ms->above_4g_mem_size, pci_memory, ram_memory); + pci_bus_map_irqs(pci_bus, + xen_enabled() ? xen_pci_slot_get_pirq + : pc_pci_slot_get_pirq); pcms->bus = pci_bus; pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, type); diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 666e794f77..283b971ec4 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -79,17 +79,6 @@ static void piix3_set_irq(void *opaque, int pirq, int level) piix3_set_irq_level(piix3, pirq, level); } -/* - * Return the global irq number corresponding to a given device irq - * pin. We could also use the bus number to have a more precise mapping. - */ -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) -{ - int slot_addend; - slot_addend = PCI_SLOT(pci_dev->devfn) - 1; - return (pci_intx + slot_addend) & 3; -} - static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin) { PIIX3State *piix3 = opaque; @@ -385,7 +374,6 @@ static void piix3_realize(PCIDevice *dev, Error **errp) } pci_bus_irqs(pci_bus, piix3_set_irq, piix3, PIIX_NUM_PIRQS); - pci_bus_map_irqs(pci_bus, pci_slot_get_pirq); pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq); } @@ -421,7 +409,6 @@ static void piix3_xen_realize(PCIDevice *dev, Error **errp) * These additional routes can be discovered through ACPI. */ pci_bus_irqs(pci_bus, xen_piix3_set_irq, piix3, XEN_PIIX_NUM_PIRQS); - pci_bus_map_irqs(pci_bus, xen_pci_slot_get_pirq); } static void piix3_xen_class_init(ObjectClass *klass, void *data) From 3c73d590e7b20c58061cc7a67ecc6e3f5bf39192 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:19 +0100 Subject: [PATCH 032/814] hw/isa/piix4: Decouple INTx-to-LNKx routing which is board-specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_map_irq_fn's in general seem to be board-specific, and PIIX4's pci_slot_get_pirq() in particular seems very Malta-specific. So move the latter to malta.c to 1/ keep the board logic in one place and 2/ avoid PIIX4 to make assumptions about its board. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109172347.1830-7-shentey@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/isa/piix4.c | 26 -------------------------- hw/mips/malta.c | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 9c79c9677b..6e9434129d 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -79,31 +79,6 @@ static void piix4_set_irq(void *opaque, int irq_num, int level) } } -static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot; - - slot = PCI_SLOT(pci_dev->devfn); - - switch (slot) { - /* PIIX4 USB */ - case 10: - return 3; - /* AMD 79C973 Ethernet */ - case 11: - return 1; - /* Crystal 4281 Sound */ - case 12: - return 2; - /* PCI slot 1 to 4 */ - case 18 ... 21: - return ((slot - 18) + irq_num) & 0x03; - /* Unknown device, don't do any translation */ - default: - return irq_num; - } -} - static void piix4_isa_reset(DeviceState *dev) { PIIX4State *d = PIIX4_PCI_DEVICE(dev); @@ -272,7 +247,6 @@ static void piix4_realize(PCIDevice *dev, Error **errp) qdev_connect_gpio_out(DEVICE(&s->pm), 0, s->isa[9]); pci_bus_irqs(pci_bus, piix4_set_irq, s, PIIX_NUM_PIRQS); - pci_bus_map_irqs(pci_bus, pci_slot_get_pirq); } static void piix4_init(Object *obj) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 8bf2e2ff5f..ec172b111a 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -39,6 +39,7 @@ #include "hw/mips/bootloader.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "qemu/log.h" #include "hw/mips/bios.h" #include "hw/ide/pci.h" @@ -993,6 +994,31 @@ static void malta_mips_config(MIPSCPU *cpu) } } +static int malta_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot; + + slot = PCI_SLOT(pci_dev->devfn); + + switch (slot) { + /* PIIX4 USB */ + case 10: + return 3; + /* AMD 79C973 Ethernet */ + case 11: + return 1; + /* Crystal 4281 Sound */ + case 12: + return 2; + /* PCI slot 1 to 4 */ + case 18 ... 21: + return ((slot - 18) + irq_num) & 0x03; + /* Unknown device, don't do any translation */ + default: + return irq_num; + } +} + static void main_cpu_reset(void *opaque) { MIPSCPU *cpu = opaque; @@ -1225,6 +1251,7 @@ void mips_malta_init(MachineState *machine) qdev_prop_set_bit(dev, "cpu-little-endian", !be); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); + pci_bus_map_irqs(pci_bus, malta_pci_slot_get_pirq); /* Southbridge */ piix4 = pci_create_simple_multifunction(pci_bus, PIIX4_PCI_DEVFN, true, From c451e07798e3640bed992cb43d8d867ef0ae1f4a Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:20 +0100 Subject: [PATCH 033/814] hw/mips/Kconfig: Track Malta's PIIX dependencies via Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tracking dependencies via Kconfig seems much cleaner. Note that PIIX4 already depends on ACPI_PIIX4. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20230109172347.1830-8-shentey@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- configs/devices/mips-softmmu/common.mak | 2 -- hw/mips/Kconfig | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/configs/devices/mips-softmmu/common.mak b/configs/devices/mips-softmmu/common.mak index a125e74f24..7da99327a7 100644 --- a/configs/devices/mips-softmmu/common.mak +++ b/configs/devices/mips-softmmu/common.mak @@ -17,9 +17,7 @@ CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y CONFIG_FDC=y -CONFIG_ACPI_PIIX4=y CONFIG_I8257=y -CONFIG_PIIX4=y CONFIG_IDE_ISA=y CONFIG_PFLASH_CFI01=y CONFIG_I8259=y diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 7a55143f8a..da3a37e215 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -2,6 +2,7 @@ config MALTA bool select GT64120 select ISA_SUPERIO + select PIIX4 config MIPSSIM bool From f0712099a29aba335fd1dbf4b19811ad0f57d095 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:21 +0100 Subject: [PATCH 034/814] hw/usb/hcd-uhci: Introduce TYPE_ defines for device models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Mark Cave-Ayland Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20221204190553.3274-7-shentey@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_piix.c | 3 ++- hw/i386/pc_q35.c | 13 +++++++------ hw/isa/piix4.c | 2 +- hw/usb/hcd-uhci.c | 16 ++++++++-------- hw/usb/hcd-uhci.h | 4 ++++ 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index bb3b10557f..df64dd8dcc 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -51,6 +51,7 @@ #include "exec/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/piix4.h" +#include "hw/usb/hcd-uhci.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/xen.h" @@ -305,7 +306,7 @@ static void pc_init1(MachineState *machine, #endif if (pcmc->pci_enabled && machine_usb(machine)) { - pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); + pci_create_simple(pci_bus, piix3_devfn + 2, TYPE_PIIX3_USB_UHCI); } if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 65ea226211..83c57c6eb1 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -48,6 +48,7 @@ #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" +#include "hw/usb/hcd-uhci.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/numa.h" @@ -65,15 +66,15 @@ struct ehci_companions { }; static const struct ehci_companions ich9_1d[] = { - { .name = "ich9-usb-uhci1", .func = 0, .port = 0 }, - { .name = "ich9-usb-uhci2", .func = 1, .port = 2 }, - { .name = "ich9-usb-uhci3", .func = 2, .port = 4 }, + { .name = TYPE_ICH9_USB_UHCI(1), .func = 0, .port = 0 }, + { .name = TYPE_ICH9_USB_UHCI(2), .func = 1, .port = 2 }, + { .name = TYPE_ICH9_USB_UHCI(3), .func = 2, .port = 4 }, }; static const struct ehci_companions ich9_1a[] = { - { .name = "ich9-usb-uhci4", .func = 0, .port = 0 }, - { .name = "ich9-usb-uhci5", .func = 1, .port = 2 }, - { .name = "ich9-usb-uhci6", .func = 2, .port = 4 }, + { .name = TYPE_ICH9_USB_UHCI(4), .func = 0, .port = 0 }, + { .name = TYPE_ICH9_USB_UHCI(5), .func = 1, .port = 2 }, + { .name = TYPE_ICH9_USB_UHCI(6), .func = 2, .port = 4 }, }; static int ehci_create_ich9_with_companions(PCIBus *bus, int slot) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 6e9434129d..de60ceef73 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -255,7 +255,7 @@ static void piix4_init(Object *obj) object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC); object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); - object_initialize_child(obj, "uhci", &s->uhci, "piix4-usb-uhci"); + object_initialize_child(obj, "uhci", &s->uhci, TYPE_PIIX4_USB_UHCI); object_initialize_child(obj, "pm", &s->pm, TYPE_PIIX4_PM); qdev_prop_set_uint32(DEVICE(&s->pm), "smb_io_base", 0x1100); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index d1b5657d72..30ae0104bb 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1292,56 +1292,56 @@ void uhci_data_class_init(ObjectClass *klass, void *data) static UHCIInfo uhci_info[] = { { - .name = "piix3-usb-uhci", + .name = TYPE_PIIX3_USB_UHCI, .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, .revision = 0x01, .irq_pin = 3, .unplug = true, },{ - .name = "piix4-usb-uhci", + .name = TYPE_PIIX4_USB_UHCI, .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, .revision = 0x01, .irq_pin = 3, .unplug = true, },{ - .name = "ich9-usb-uhci1", /* 00:1d.0 */ + .name = TYPE_ICH9_USB_UHCI(1), /* 00:1d.0 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, .revision = 0x03, .irq_pin = 0, .unplug = false, },{ - .name = "ich9-usb-uhci2", /* 00:1d.1 */ + .name = TYPE_ICH9_USB_UHCI(2), /* 00:1d.1 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, .revision = 0x03, .irq_pin = 1, .unplug = false, },{ - .name = "ich9-usb-uhci3", /* 00:1d.2 */ + .name = TYPE_ICH9_USB_UHCI(3), /* 00:1d.2 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, .revision = 0x03, .irq_pin = 2, .unplug = false, },{ - .name = "ich9-usb-uhci4", /* 00:1a.0 */ + .name = TYPE_ICH9_USB_UHCI(4), /* 00:1a.0 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4, .revision = 0x03, .irq_pin = 0, .unplug = false, },{ - .name = "ich9-usb-uhci5", /* 00:1a.1 */ + .name = TYPE_ICH9_USB_UHCI(5), /* 00:1a.1 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5, .revision = 0x03, .irq_pin = 1, .unplug = false, },{ - .name = "ich9-usb-uhci6", /* 00:1a.2 */ + .name = TYPE_ICH9_USB_UHCI(6), /* 00:1a.2 */ .vendor_id = PCI_VENDOR_ID_INTEL, .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6, .revision = 0x03, diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h index 5843af504a..e0fdb98ef1 100644 --- a/hw/usb/hcd-uhci.h +++ b/hw/usb/hcd-uhci.h @@ -91,4 +91,8 @@ typedef struct UHCIInfo { void uhci_data_class_init(ObjectClass *klass, void *data); void usb_uhci_common_realize(PCIDevice *dev, Error **errp); +#define TYPE_PIIX3_USB_UHCI "piix3-usb-uhci" +#define TYPE_PIIX4_USB_UHCI "piix4-usb-uhci" +#define TYPE_ICH9_USB_UHCI(fn) "ich9-usb-uhci" #fn + #endif From 2aaf0ec7ff239523ce2c8d913b120202c219af3e Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 9 Jan 2023 18:23:22 +0100 Subject: [PATCH 035/814] hw/intc/i8259: Make using the isa_pic singleton more type-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This even spares some casts in hot code paths along the way. Signed-off-by: Bernhard Beschow Reviewed-by: Michael S. Tsirkin Reviewed-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109172347.1830-10-shentey@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/i8259.c | 11 ++++------- include/hw/intc/i8259.h | 6 +++--- include/qemu/typedefs.h | 1 + 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index cc4e21ffec..0261f087b2 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -55,7 +55,7 @@ struct PICClass { #ifdef DEBUG_IRQ_LATENCY static int64_t irq_time[16]; #endif -DeviceState *isa_pic; +PICCommonState *isa_pic; static PICCommonState *slave_pic; /* return the highest priority found in mask (highest = smallest @@ -173,9 +173,8 @@ static void pic_intack(PICCommonState *s, int irq) pic_update_irq(s); } -int pic_read_irq(DeviceState *d) +int pic_read_irq(PICCommonState *s) { - PICCommonState *s = PIC_COMMON(d); int irq, intno; irq = pic_get_irq(s); @@ -354,10 +353,8 @@ static uint64_t pic_ioport_read(void *opaque, hwaddr addr, return ret; } -int pic_get_output(DeviceState *d) +int pic_get_output(PICCommonState *s) { - PICCommonState *s = PIC_COMMON(d); - return (pic_get_irq(s) >= 0); } @@ -426,7 +423,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) irq_set[i] = qdev_get_gpio_in(dev, i); } - isa_pic = dev; + isa_pic = PIC_COMMON(dev); isadev = i8259_init_chip(TYPE_I8259, bus, false); dev = DEVICE(isadev); diff --git a/include/hw/intc/i8259.h b/include/hw/intc/i8259.h index e2b1e8c59a..a0e34dd990 100644 --- a/include/hw/intc/i8259.h +++ b/include/hw/intc/i8259.h @@ -3,10 +3,10 @@ /* i8259.c */ -extern DeviceState *isa_pic; +extern PICCommonState *isa_pic; qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); qemu_irq *kvm_i8259_init(ISABus *bus); -int pic_get_output(DeviceState *d); -int pic_read_irq(DeviceState *d); +int pic_get_output(PICCommonState *s); +int pic_read_irq(PICCommonState *s); #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 073abab998..fba04875c2 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -99,6 +99,7 @@ typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIHostDeviceAddress PCIHostDeviceAddress; typedef struct PCIHostState PCIHostState; +typedef struct PICCommonState PICCommonState; typedef struct PostcopyDiscardState PostcopyDiscardState; typedef struct Property Property; typedef struct PropertyInfo PropertyInfo; From 2b85e0cda4b066010efda63a2d2359872ba07a04 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 10 Jan 2023 10:53:48 +0100 Subject: [PATCH 036/814] hw/intc: Extract the IRQ counting functions into a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These IRQ counting functions will soon be required in binaries that do not include the APIC code, too, so let's extract them into a separate file that can be linked independently of the APIC code. While we're at it, change the apic_* prefix into kvm_* since the functions are used from the i8259 PIC (i.e. not the APIC), too. Reviewed-by: Bernhard Beschow Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20230110095351.611724-2-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/kvm/i8259.c | 4 +-- hw/i386/kvm/ioapic.c | 4 +-- hw/intc/apic.c | 3 +- hw/intc/apic_common.c | 30 ++------------------ hw/intc/kvm_irqcount.c | 49 +++++++++++++++++++++++++++++++++ hw/intc/meson.build | 6 ++++ hw/intc/trace-events | 9 +++--- hw/rtc/mc146818rtc.c | 6 ++-- include/hw/i386/apic.h | 2 -- include/hw/i386/apic_internal.h | 1 - include/hw/intc/kvm_irqcount.h | 10 +++++++ 11 files changed, 81 insertions(+), 43 deletions(-) create mode 100644 hw/intc/kvm_irqcount.c create mode 100644 include/hw/intc/kvm_irqcount.h diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index d61bae4dc3..3ca0e1ff03 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -14,7 +14,7 @@ #include "hw/isa/i8259_internal.h" #include "hw/intc/i8259.h" #include "qemu/module.h" -#include "hw/i386/apic_internal.h" +#include "hw/intc/kvm_irqcount.h" #include "hw/irq.h" #include "sysemu/kvm.h" #include "qom/object.h" @@ -117,7 +117,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level) pic_stat_update_irq(irq, level); delivered = kvm_set_irq(kvm_state, irq, level); - apic_report_irq_delivered(delivered); + kvm_report_irq_delivered(delivered); } static void kvm_pic_realize(DeviceState *dev, Error **errp) diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index ee7c8ef68b..272e26b4a2 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -15,7 +15,7 @@ #include "hw/i386/x86.h" #include "hw/qdev-properties.h" #include "hw/i386/ioapic_internal.h" -#include "hw/i386/apic_internal.h" +#include "hw/intc/kvm_irqcount.h" #include "sysemu/kvm.h" /* PC Utility function */ @@ -116,7 +116,7 @@ static void kvm_ioapic_set_irq(void *opaque, int irq, int level) ioapic_stat_update_irq(common, irq, level); delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level); - apic_report_irq_delivered(delivered); + kvm_report_irq_delivered(delivered); } static void kvm_ioapic_realize(DeviceState *dev, Error **errp) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 3df11c34d6..2d3e55f4e2 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -22,6 +22,7 @@ #include "hw/i386/apic.h" #include "hw/i386/ioapic.h" #include "hw/intc/i8259.h" +#include "hw/intc/kvm_irqcount.h" #include "hw/pci/msi.h" #include "qemu/host-utils.h" #include "sysemu/kvm.h" @@ -399,7 +400,7 @@ void apic_poll_irq(DeviceState *dev) static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) { - apic_report_irq_delivered(!apic_get_bit(s->irr, vector_num)); + kvm_report_irq_delivered(!apic_get_bit(s->irr, vector_num)); apic_set_bit(s->irr, vector_num); if (trigger_mode) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 2a20982066..4a34f03047 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -25,6 +25,7 @@ #include "qapi/visitor.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" +#include "hw/intc/kvm_irqcount.h" #include "trace.h" #include "hw/boards.h" #include "sysemu/hax.h" @@ -33,7 +34,6 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" -static int apic_irq_delivered; bool apic_report_tpr_access; void cpu_set_apic_base(DeviceState *dev, uint64_t val) @@ -122,32 +122,6 @@ void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip, vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access); } -void apic_report_irq_delivered(int delivered) -{ - apic_irq_delivered += delivered; - - trace_apic_report_irq_delivered(apic_irq_delivered); -} - -void apic_reset_irq_delivered(void) -{ - /* Copy this into a local variable to encourage gcc to emit a plain - * register for a sys/sdt.h marker. For details on this workaround, see: - * https://sourceware.org/bugzilla/show_bug.cgi?id=13296 - */ - volatile int a_i_d = apic_irq_delivered; - trace_apic_reset_irq_delivered(a_i_d); - - apic_irq_delivered = 0; -} - -int apic_get_irq_delivered(void) -{ - trace_apic_get_irq_delivered(apic_irq_delivered); - - return apic_irq_delivered; -} - void apic_deliver_nmi(DeviceState *dev) { APICCommonState *s = APIC_COMMON(dev); @@ -272,7 +246,7 @@ static void apic_reset_common(DeviceState *dev) s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE; s->id = s->initial_apic_id; - apic_reset_irq_delivered(); + kvm_reset_irq_delivered(); s->vapic_paddr = 0; info->vapic_base_update(s); diff --git a/hw/intc/kvm_irqcount.c b/hw/intc/kvm_irqcount.c new file mode 100644 index 0000000000..2ef8a83a7a --- /dev/null +++ b/hw/intc/kvm_irqcount.c @@ -0,0 +1,49 @@ +/* + * KVM PIC functions for counting the delivered IRQs. + * + * 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 "qemu/osdep.h" +#include "hw/intc/kvm_irqcount.h" +#include "trace.h" + +static int kvm_irq_delivered; + +void kvm_report_irq_delivered(int delivered) +{ + kvm_irq_delivered += delivered; + + trace_kvm_report_irq_delivered(kvm_irq_delivered); +} + +void kvm_reset_irq_delivered(void) +{ + /* + * Copy this into a local variable to encourage gcc to emit a plain + * register for a sys/sdt.h marker. For details on this workaround, see: + * https://sourceware.org/bugzilla/show_bug.cgi?id=13296 + */ + volatile int k_i_d = kvm_irq_delivered; + trace_kvm_reset_irq_delivered(k_i_d); + + kvm_irq_delivered = 0; +} + +int kvm_get_irq_delivered(void) +{ + trace_kvm_get_irq_delivered(kvm_irq_delivered); + + return kvm_irq_delivered; +} diff --git a/hw/intc/meson.build b/hw/intc/meson.build index bcbf22ff51..cd9f1ee888 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -25,6 +25,12 @@ softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-ipi.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_PMU', if_true: files('xlnx-pmu-iomod-intc.c')) +if config_all_devices.has_key('CONFIG_APIC') or \ + config_all_devices.has_key('CONFIG_I8259') or \ + config_all_devices.has_key('CONFIG_MC146818RTC') + softmmu_ss.add(files('kvm_irqcount.c')) +endif + specific_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c')) specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c')) specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 6fbc2045e6..50cadfb996 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -10,10 +10,6 @@ pic_ioport_read(bool master, uint64_t addr, int val) "master %d addr 0x%"PRIx64" # apic_common.c cpu_set_apic_base(uint64_t val) "0x%016"PRIx64 cpu_get_apic_base(uint64_t val) "0x%016"PRIx64 -# coalescing -apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d" -apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d" -apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d" # apic.c apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d" @@ -30,6 +26,11 @@ ioapic_mem_read(uint8_t addr, uint8_t regsel, uint8_t size, uint32_t val) "ioapi ioapic_mem_write(uint8_t addr, uint8_t regsel, uint8_t size, uint32_t val) "ioapic mem write addr 0x%"PRIx8" regsel: 0x%"PRIx8" size 0x%"PRIx8" val 0x%"PRIx32 ioapic_set_irq(int vector, int level) "vector: %d level: %d" +# kvm_irqcount.c +kvm_report_irq_delivered(int irq_delivered) "coalescing %d" +kvm_reset_irq_delivered(int irq_delivered) "old coalescing %d" +kvm_get_irq_delivered(int irq_delivered) "returning coalescing %d" + # slavio_intctl.c slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = 0x%x" slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = 0x%x" diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 1ebb412479..947d68c257 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -27,6 +27,7 @@ #include "qemu/module.h" #include "qemu/bcd.h" #include "hw/acpi/acpi_aml_interface.h" +#include "hw/intc/kvm_irqcount.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" @@ -46,7 +47,6 @@ #ifdef TARGET_I386 #include "qapi/qapi-commands-misc-target.h" -#include "hw/i386/apic.h" #endif //#define DEBUG_CMOS @@ -124,9 +124,9 @@ void qmp_rtc_reset_reinjection(Error **errp) static bool rtc_policy_slew_deliver_irq(RTCState *s) { - apic_reset_irq_delivered(); + kvm_reset_irq_delivered(); qemu_irq_raise(s->irq); - return apic_get_irq_delivered(); + return kvm_get_irq_delivered(); } static void rtc_coalesced_timer(void *opaque) diff --git a/include/hw/i386/apic.h b/include/hw/i386/apic.h index da1d2fe155..bdc15a7a73 100644 --- a/include/hw/i386/apic.h +++ b/include/hw/i386/apic.h @@ -9,8 +9,6 @@ int apic_accept_pic_intr(DeviceState *s); void apic_deliver_pic_intr(DeviceState *s, int level); void apic_deliver_nmi(DeviceState *d); int apic_get_interrupt(DeviceState *s); -void apic_reset_irq_delivered(void); -int apic_get_irq_delivered(void); void cpu_set_apic_base(DeviceState *s, uint64_t val); uint64_t cpu_get_apic_base(DeviceState *s); void cpu_set_apic_tpr(DeviceState *s, uint8_t val); diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 968b6648b3..5f2ba24bfc 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -199,7 +199,6 @@ typedef struct VAPICState { extern bool apic_report_tpr_access; -void apic_report_irq_delivered(int delivered); bool apic_next_timer(APICCommonState *s, int64_t current_time); void apic_enable_tpr_access_reporting(DeviceState *d, bool enable); void apic_enable_vapic(DeviceState *d, hwaddr paddr); diff --git a/include/hw/intc/kvm_irqcount.h b/include/hw/intc/kvm_irqcount.h new file mode 100644 index 0000000000..0ed5999e49 --- /dev/null +++ b/include/hw/intc/kvm_irqcount.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef KVM_IRQCOUNT_H +#define KVM_IRQCOUNT_H + +void kvm_report_irq_delivered(int delivered); +void kvm_reset_irq_delivered(void); +int kvm_get_irq_delivered(void); + +#endif From aae167211fb326784b323b87a0e4c0fa832940b3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 10 Jan 2023 10:53:49 +0100 Subject: [PATCH 037/814] hw/core/qdev-properties-system: Allow the 'slew' policy only on x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'slew' tick policy is currently enforced to be only available on x86 via some "#ifdef TARGET_I386" statements in mc146818rtc.c. We want to get rid of those #ifdefs, so we need a different way of checking whether the policy is allowed or not. Using the setter function in hw/core/qdev-properties-system.c seems to be a good place, so let's add a check here. Suggested-by: Mark Cave-Ayland Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Reviewed-by: Bernhard Beschow Message-Id: <20230110095351.611724-3-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/qdev-properties-system.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 54a09fa9ac..d42493f630 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -33,6 +33,7 @@ #include "net/net.h" #include "hw/pci/pci.h" #include "hw/pci/pcie.h" +#include "hw/i386/x86.h" #include "util/block-helpers.h" static bool check_prop_still_unset(Object *obj, const char *name, @@ -558,13 +559,38 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) /* --- lost tick policy --- */ +static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Property *prop = opaque; + int *ptr = object_field_prop_ptr(obj, prop); + int value; + + if (!visit_type_enum(v, name, &value, prop->info->enum_table, errp)) { + return; + } + + if (value == LOST_TICK_POLICY_SLEW) { + MachineState *ms = MACHINE(qdev_get_machine()); + + if (!object_dynamic_cast(OBJECT(ms), TYPE_X86_MACHINE)) { + error_setg(errp, + "the 'slew' policy is only available for x86 machines"); + return; + } + } + + *ptr = value; +} + QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); const PropertyInfo qdev_prop_losttickpolicy = { .name = "LostTickPolicy", .enum_table = &LostTickPolicy_lookup, .get = qdev_propinfo_get_enum, - .set = qdev_propinfo_set_enum, + .set = qdev_propinfo_set_losttickpolicy, .set_default_value = qdev_propinfo_set_default_value_enum, }; From e896d849331eb853cf3b7df6a24be279ae9a421d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 10 Jan 2023 10:53:50 +0100 Subject: [PATCH 038/814] hw/rtc/mc146818rtc: Make the mc146818 RTC device target independent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only reason for this code being target dependent was the IRQ-counting related code in rtc_policy_slew_deliver_irq(). Since these functions have been moved into a new, separate file (kvm_irqcount.c) which is now always compiled and linked if necessary, we can get rid of the #ifdef TARGET_I386 switches in mc146818rtc.c and declare it in the softmmu_ss instead of specific_ss, so that the code only gets compiled once for all targets. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20230110095351.611724-4-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/rtc/mc146818rtc.c | 14 -------------- hw/rtc/meson.build | 3 +-- include/hw/rtc/mc146818rtc.h | 1 + 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 947d68c257..bc1192b7ae 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -45,10 +45,6 @@ #include "qapi/visitor.h" #include "hw/rtc/mc146818rtc_regs.h" -#ifdef TARGET_I386 -#include "qapi/qapi-commands-misc-target.h" -#endif - //#define DEBUG_CMOS //#define DEBUG_COALESCED @@ -112,7 +108,6 @@ static void rtc_coalesced_timer_update(RTCState *s) static QLIST_HEAD(, RTCState) rtc_devices = QLIST_HEAD_INITIALIZER(rtc_devices); -#ifdef TARGET_I386 void qmp_rtc_reset_reinjection(Error **errp) { RTCState *s; @@ -145,13 +140,6 @@ static void rtc_coalesced_timer(void *opaque) rtc_coalesced_timer_update(s); } -#else -static bool rtc_policy_slew_deliver_irq(RTCState *s) -{ - assert(0); - return false; -} -#endif static uint32_t rtc_periodic_clock_ticks(RTCState *s) { @@ -922,12 +910,10 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) rtc_set_date_from_host(isadev); switch (s->lost_tick_policy) { -#ifdef TARGET_I386 case LOST_TICK_POLICY_SLEW: s->coalesced_timer = timer_new_ns(rtc_clock, rtc_coalesced_timer, s); break; -#endif case LOST_TICK_POLICY_DISCARD: break; default: diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build index dc33973384..34a4d316fa 100644 --- a/hw/rtc/meson.build +++ b/hw/rtc/meson.build @@ -13,5 +13,4 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c')) softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c')) softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c')) - -specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c')) +softmmu_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c')) diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h index 1db0fcee92..45bcd6f040 100644 --- a/include/hw/rtc/mc146818rtc.h +++ b/include/hw/rtc/mc146818rtc.h @@ -55,5 +55,6 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); int rtc_get_memory(ISADevice *dev, int addr); +void qmp_rtc_reset_reinjection(Error **errp); #endif /* HW_RTC_MC146818RTC_H */ From e8dc34196b2a81b21469f6d95afc390ef645e63b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 10 Jan 2023 10:53:51 +0100 Subject: [PATCH 039/814] softmmu/rtc: Emit warning when using driftfix=slew on systems without mc146818 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'slew' lost tick policy is only available on systems with a mc146818 RTC. On other systems, "-rtc driftfix=slew" is currently silently ignored. Let's emit at least a warning in this case to make the users aware that there is something wrong in their command line settings. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Reviewed-by: Mark Cave-Ayland Message-Id: <20230110095351.611724-5-thuth@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- softmmu/rtc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/softmmu/rtc.c b/softmmu/rtc.c index 7e2956f81e..f7114bed7d 100644 --- a/softmmu/rtc.c +++ b/softmmu/rtc.c @@ -33,6 +33,7 @@ #include "sysemu/replay.h" #include "sysemu/sysemu.h" #include "sysemu/rtc.h" +#include "hw/rtc/mc146818rtc.h" static enum { RTC_BASE_UTC, @@ -177,10 +178,13 @@ void configure_rtc(QemuOpts *opts) value = qemu_opt_get(opts, "driftfix"); if (value) { if (!strcmp(value, "slew")) { - object_register_sugar_prop("mc146818rtc", + object_register_sugar_prop(TYPE_MC146818_RTC, "lost_tick_policy", "slew", false); + if (!object_class_by_name(TYPE_MC146818_RTC)) { + warn_report("driftfix 'slew' is not available with this machine"); + } } else if (!strcmp(value, "none")) { /* discard is default */ } else { From 4dd5cb5d847ed887dd0a00c602b08bade6f6ffa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 26 Sep 2019 15:42:11 +0200 Subject: [PATCH 040/814] hw/pci-host/bonito: Convert to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_PCI_BONITO class to use 3-phase reset. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230105130710.49264-2-philmd@linaro.org> --- hw/pci-host/bonito.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index f04f3ad668..450eb29ec0 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -47,7 +47,6 @@ #include "hw/mips/mips.h" #include "hw/pci/pci_host.h" #include "migration/vmstate.h" -#include "sysemu/reset.h" #include "sysemu/runstate.h" #include "hw/misc/unimp.h" #include "hw/registerfields.h" @@ -593,9 +592,9 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num) } } -static void bonito_reset(void *opaque) +static void bonito_reset_hold(Object *obj) { - PCIBonitoState *s = opaque; + PCIBonitoState *s = PCI_BONITO(obj); uint32_t val = 0; /* set the default value of north bridge registers */ @@ -739,8 +738,6 @@ static void bonito_realize(PCIDevice *dev, Error **errp) pci_set_byte(dev->config + PCI_MIN_GNT, 0x3c); pci_set_byte(dev->config + PCI_MAX_LAT, 0x00); - - qemu_register_reset(bonito_reset, s); } PCIBus *bonito_init(qemu_irq *pic) @@ -770,7 +767,9 @@ static void bonito_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + rc->phases.hold = bonito_reset_hold; k->realize = bonito_realize; k->vendor_id = 0xdf53; k->device_id = 0x00d5; From f9ab9c6e2b6091f1be519852eb2552a96e800a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Jan 2023 11:47:04 +0100 Subject: [PATCH 041/814] hw/pci-host/bonito: Use 'bonito_host' for PCI host bridge code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make it easier to differentiate between the Host Bridge object and its PCI function #0, rename bonito_pcihost* as bonito_host*. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230105130710.49264-3-philmd@linaro.org> --- hw/pci-host/bonito.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 450eb29ec0..5c0928ffe6 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -627,7 +627,7 @@ static const VMStateDescription vmstate_bonito = { } }; -static void bonito_pcihost_realize(DeviceState *dev, Error **errp) +static void bonito_host_realize(DeviceState *dev, Error **errp) { PCIHostState *phb = PCI_HOST_BRIDGE(dev); BonitoState *bs = BONITO_PCI_HOST_BRIDGE(dev); @@ -795,23 +795,23 @@ static const TypeInfo bonito_info = { }, }; -static void bonito_pcihost_class_init(ObjectClass *klass, void *data) +static void bonito_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = bonito_pcihost_realize; + dc->realize = bonito_host_realize; } -static const TypeInfo bonito_pcihost_info = { +static const TypeInfo bonito_host_info = { .name = TYPE_BONITO_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(BonitoState), - .class_init = bonito_pcihost_class_init, + .class_init = bonito_host_class_init, }; static void bonito_register_types(void) { - type_register_static(&bonito_pcihost_info); + type_register_static(&bonito_host_info); type_register_static(&bonito_info); } From eb66dac46da958c0ba20a2803344b20c8f79c48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Jan 2023 11:48:34 +0100 Subject: [PATCH 042/814] hw/pci-host/bonito: Use 'bonito_pci' for PCI function #0 code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make it easier to differentiate between the Host Bridge object and its PCI function #0, rename bonito* as bonito_pci*. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230105130710.49264-4-philmd@linaro.org> --- hw/pci-host/bonito.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 5c0928ffe6..9c26aa2ad9 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -653,7 +653,7 @@ static void bonito_host_realize(DeviceState *dev, Error **errp) create_unimplemented_device("pci.io", BONITO_PCIIO_BASE, 1 * MiB); } -static void bonito_realize(PCIDevice *dev, Error **errp) +static void bonito_pci_realize(PCIDevice *dev, Error **errp) { PCIBonitoState *s = PCI_BONITO(dev); SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost); @@ -763,14 +763,14 @@ PCIBus *bonito_init(qemu_irq *pic) return phb->bus; } -static void bonito_class_init(ObjectClass *klass, void *data) +static void bonito_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); rc->phases.hold = bonito_reset_hold; - k->realize = bonito_realize; + k->realize = bonito_pci_realize; k->vendor_id = 0xdf53; k->device_id = 0x00d5; k->revision = 0x01; @@ -784,11 +784,11 @@ static void bonito_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static const TypeInfo bonito_info = { +static const TypeInfo bonito_pci_info = { .name = TYPE_PCI_BONITO, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBonitoState), - .class_init = bonito_class_init, + .class_init = bonito_pci_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, @@ -812,7 +812,7 @@ static const TypeInfo bonito_host_info = { static void bonito_register_types(void) { type_register_static(&bonito_host_info); - type_register_static(&bonito_info); + type_register_static(&bonito_pci_info); } type_init(bonito_register_types) From aad07969bb3bd7771678143119e53b86829f8746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Jan 2023 13:48:08 +0100 Subject: [PATCH 043/814] hw/pci-host/bonito: Declare TYPE_BONITO_PCI_HOST_BRIDGE in header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare the TYPE_BONITO_PCI_HOST_BRIDGE QOM type in a header to be able to access it from board code. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230105130710.49264-8-philmd@linaro.org> --- MAINTAINERS | 1 + hw/pci-host/bonito.c | 4 +--- include/hw/pci-host/bonito.h | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 include/hw/pci-host/bonito.h diff --git a/MAINTAINERS b/MAINTAINERS index a670fbc926..f7f5e9e439 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1262,6 +1262,7 @@ F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c F: hw/usb/vt82c686-uhci-pci.c F: include/hw/isa/vt82c686.h +F: include/hw/pci-host/bonito.h F: tests/avocado/machine_mips_fuloong2e.py Loongson-3 virtual platforms diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 9c26aa2ad9..ac1eebf9de 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -45,6 +45,7 @@ #include "hw/pci/pci_device.h" #include "hw/irq.h" #include "hw/mips/mips.h" +#include "hw/pci-host/bonito.h" #include "hw/pci/pci_host.h" #include "migration/vmstate.h" #include "sysemu/runstate.h" @@ -238,9 +239,6 @@ struct BonitoState { MemoryRegion pci_mem; }; -#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost" -OBJECT_DECLARE_SIMPLE_TYPE(BonitoState, BONITO_PCI_HOST_BRIDGE) - #define TYPE_PCI_BONITO "Bonito" OBJECT_DECLARE_SIMPLE_TYPE(PCIBonitoState, PCI_BONITO) diff --git a/include/hw/pci-host/bonito.h b/include/hw/pci-host/bonito.h new file mode 100644 index 0000000000..b8ecf7870a --- /dev/null +++ b/include/hw/pci-host/bonito.h @@ -0,0 +1,18 @@ +/* + * QEMU Bonito64 north bridge support + * + * Copyright (c) 2008 yajin (yajin@vm-kernel.org) + * Copyright (c) 2010 Huacai Chen (zltjiangshi@gmail.com) + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_PCI_HOST_BONITO_H +#define HW_PCI_HOST_BONITO_H + +#include "qom/object.h" + +#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(BonitoState, BONITO_PCI_HOST_BRIDGE) + +#endif From 026334610f40fe8c0abac9565eddee1d6cc99de7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:21:33 -0300 Subject: [PATCH 044/814] hw/mips/boston: Rename MachineState 'mc' pointer to 'ms' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the QEMU convention of naming MachineState pointers as 'ms' by renaming the instance in create_fdt() where we're calling it 'mc'. Cc: Paul Burton Cc: Aleksandar Rikalo Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Message-Id: <20230111172133.334735-1-dbarboza@ventanamicro.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/mips/boston.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips/boston.c b/hw/mips/boston.c index b6dd9fb200..a9d87f3437 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -515,7 +515,7 @@ static const void *create_fdt(BostonState *s, { void *fdt; int cpu; - MachineState *mc = s->mach; + MachineState *ms = s->mach; uint32_t platreg_ph, gic_ph, clk_ph; char *name, *gic_name, *platreg_name, *stdout_name; static const char * const syscon_compat[2] = { @@ -542,7 +542,7 @@ static const void *create_fdt(BostonState *s, qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); - for (cpu = 0; cpu < mc->smp.cpus; cpu++) { + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { name = g_strdup_printf("/cpus/cpu@%d", cpu); qemu_fdt_add_subnode(fdt, name); qemu_fdt_setprop_string(fdt, name, "compatible", "img,mips"); From 6ba97c48a64d059ddfa5400330dfaf5982f5f2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Dec 2022 12:14:46 +0100 Subject: [PATCH 045/814] target/mips: Restrict 'qapi-commands-machine.h' to system emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit a0e61807a3 ("qapi: Remove QMP events and commands from user-mode builds") we don't generate the "qapi-commands-machine.h" header in a user-emulation-only build. Extract the QMP functions from cpu.c (which is always compiled) to the new 'sysemu/mips-qmp-cmds.c' unit (which is only compiled when system emulation is selected). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221219211034.70491-4-philmd@linaro.org> --- target/mips/cpu.c | 29 ---------------------- target/mips/sysemu/meson.build | 1 + target/mips/sysemu/mips-qmp-cmds.c | 39 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 29 deletions(-) create mode 100644 target/mips/sysemu/mips-qmp-cmds.c diff --git a/target/mips/cpu.c b/target/mips/cpu.c index f995e88776..05caf54999 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -32,7 +32,6 @@ #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" #include "semihosting/semihost.h" -#include "qapi/qapi-commands-machine-target.h" #include "fpu_helper.h" const char regnames[32][3] = { @@ -624,34 +623,6 @@ static void mips_cpu_register_types(void) type_init(mips_cpu_register_types) -static void mips_cpu_add_definition(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - CpuDefinitionInfoList **cpu_list = user_data; - CpuDefinitionInfo *info; - const char *typename; - - typename = object_class_get_name(oc); - info = g_malloc0(sizeof(*info)); - info->name = g_strndup(typename, - strlen(typename) - strlen("-" TYPE_MIPS_CPU)); - info->q_typename = g_strdup(typename); - - QAPI_LIST_PREPEND(*cpu_list, info); -} - -CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) -{ - CpuDefinitionInfoList *cpu_list = NULL; - GSList *list; - - list = object_class_get_list(TYPE_MIPS_CPU, false); - g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); - g_slist_free(list); - - return cpu_list; -} - /* Could be used by generic CPU object */ MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) { diff --git a/target/mips/sysemu/meson.build b/target/mips/sysemu/meson.build index cefc227582..261492de5b 100644 --- a/target/mips/sysemu/meson.build +++ b/target/mips/sysemu/meson.build @@ -3,5 +3,6 @@ mips_softmmu_ss.add(files( 'cp0.c', 'cp0_timer.c', 'machine.c', + 'mips-qmp-cmds.c', 'physaddr.c', )) diff --git a/target/mips/sysemu/mips-qmp-cmds.c b/target/mips/sysemu/mips-qmp-cmds.c new file mode 100644 index 0000000000..6db4626412 --- /dev/null +++ b/target/mips/sysemu/mips-qmp-cmds.c @@ -0,0 +1,39 @@ +/* + * QEMU MIPS CPU (monitor definitions) + * + * SPDX-FileCopyrightText: 2012 SUSE LINUX Products GmbH + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-commands-machine-target.h" +#include "cpu.h" + +static void mips_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfo *info; + const char *typename; + + typename = object_class_get_name(oc); + info = g_malloc0(sizeof(*info)); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_MIPS_CPU)); + info->q_typename = g_strdup(typename); + + QAPI_LIST_PREPEND(*cpu_list, info); +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_MIPS_CPU, false); + g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} From 4828656f65324249273ad2f2db80844ba90eeb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 16 Dec 2022 09:42:09 +0100 Subject: [PATCH 046/814] scripts/git.orderfile: Display MAINTAINERS changes first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we get custom to see MAINTAINERS changes first, we might catch missing MAINTAINERS updates easier. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20221216225505.26052-1-philmd@linaro.org> --- scripts/git.orderfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/git.orderfile b/scripts/git.orderfile index b32203b710..8edac0380b 100644 --- a/scripts/git.orderfile +++ b/scripts/git.orderfile @@ -9,6 +9,8 @@ # git config diff.orderFile scripts/git.orderfile # +MAINTAINERS + # Documentation docs/* *.rst From 3ec21437b1470cff373c002c1ebb4f70f666f0c3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:56 +0000 Subject: [PATCH 047/814] target/m68k: pass quotient directly into make_quotient() Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index fdc4937e29..0932c464fd 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -515,16 +515,10 @@ uint32_t HELPER(fmovemd_ld_postinc)(CPUM68KState *env, uint32_t addr, return fmovem_postinc(env, addr, mask, cpu_ld_float64_ra); } -static void make_quotient(CPUM68KState *env, floatx80 val) +static void make_quotient(CPUM68KState *env, int32_t quotient) { - int32_t quotient; int sign; - if (floatx80_is_any_nan(val)) { - return; - } - - quotient = floatx80_to_int32(val, &env->fp_status); sign = quotient < 0; if (sign) { quotient = -quotient; @@ -538,14 +532,22 @@ void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); - make_quotient(env, res->d); + if (floatx80_is_any_nan(res->d)) { + return; + } + + make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); } void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); - make_quotient(env, res->d); + if (floatx80_is_any_nan(res->d)) { + return; + } + + make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) From 60b598df6e3e3d76dae6967e03d4418f6aac6064 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:57 +0000 Subject: [PATCH 048/814] target/m68k: pass sign directly into make_quotient() This enables the quotient parameter to be changed from int32_t to uint32_t and also allows the extra sign logic in make_quotient() to be removed. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20230114232959.118224-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 0932c464fd..76b34b8988 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -515,39 +515,42 @@ uint32_t HELPER(fmovemd_ld_postinc)(CPUM68KState *env, uint32_t addr, return fmovem_postinc(env, addr, mask, cpu_ld_float64_ra); } -static void make_quotient(CPUM68KState *env, int32_t quotient) +static void make_quotient(CPUM68KState *env, int sign, uint32_t quotient) { - int sign; - - sign = quotient < 0; - if (sign) { - quotient = -quotient; - } - quotient = (sign << 7) | (quotient & 0x7f); env->fpsr = (env->fpsr & ~FPSR_QT_MASK) | (quotient << FPSR_QT_SHIFT); } void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { + uint32_t quotient; + int sign; + res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); + sign = extractFloatx80Sign(res->d); + quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); + make_quotient(env, sign, quotient); } void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { + uint32_t quotient; + int sign; + res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); + sign = extractFloatx80Sign(res->d); + quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); + make_quotient(env, sign, quotient); } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) From ad6dae3b3369433ab43a1b190bb3a8aacabb1bbf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:58 +0000 Subject: [PATCH 049/814] target/m68k: fix FPSR quotient byte for fmod instruction The FPSR quotient byte should be set to the value of the quotient and not the result. Switch from using floatx80_mod() to floatx80_modrem() which returns the quotient as a uint64_t which can be used for the quotient byte. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 76b34b8988..5fd094a33c 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -523,17 +523,16 @@ static void make_quotient(CPUM68KState *env, int sign, uint32_t quotient) void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - uint32_t quotient; - int sign; + uint64_t quotient; + int sign = extractFloatx80Sign(val1->d) ^ extractFloatx80Sign(val0->d); - res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); + res->d = floatx80_modrem(val1->d, val0->d, true, "ient, + &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - sign = extractFloatx80Sign(res->d); - quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); make_quotient(env, sign, quotient); } From 1a282f60a971aa86e3cdd1b7ca000790e43bb310 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:59 +0000 Subject: [PATCH 050/814] target/m68k: fix FPSR quotient byte for frem instruction The FPSR quotient byte should be set to the value of the quotient and not the result. Manually calculate the quotient in the frem helper in round to nearest even mode (note this is different from the quotient calculated internally for fmod), and use it to set the quotient byte accordingly. Signed-off-by: Mark Cave-Ayland Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1314 Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 5fd094a33c..3a37d8f584 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -538,18 +538,27 @@ void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - uint32_t quotient; - int sign; + FPReg fp_quot; + floatx80 fp_rem; - res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); + fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status); + if (!floatx80_is_any_nan(fp_rem)) { + float_status fp_status = { }; + uint32_t quotient; + int sign; - if (floatx80_is_any_nan(res->d)) { - return; + /* Calculate quotient directly using round to nearest mode */ + set_float_rounding_mode(float_round_nearest_even, &fp_status); + set_floatx80_rounding_precision( + get_floatx80_rounding_precision(&env->fp_status), &fp_status); + fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status); + + sign = extractFloatx80Sign(fp_quot.d); + quotient = floatx80_to_int32(floatx80_abs(fp_quot.d), &env->fp_status); + make_quotient(env, sign, quotient); } - sign = extractFloatx80Sign(res->d); - quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); - make_quotient(env, sign, quotient); + res->d = fp_rem; } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) From fb7e7990342e59cf67dbd895c1a1e3fb1741df7a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Dec 2022 16:30:36 +0100 Subject: [PATCH 051/814] tests/qtest/qom-test: Do not print tested properties by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're still running into the problem that some logs are cut in the gitlab-CI since they got too big. The biggest part of the log is still the output of the qom-test. Let's stop printing the properties by default to get to a saner size here. The full output can still be enabled by setting V=2 (or higher) in the environment. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221215153036.422362-1-thuth@redhat.com Signed-off-by: Peter Maydell --- tests/qtest/qom-test.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index 13510bc349..d380261f8f 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -14,6 +14,8 @@ #include "qemu/cutils.h" #include "libqtest.h" +static bool verbose; + static void test_properties(QTestState *qts, const char *path, bool recurse) { char *child_path; @@ -49,7 +51,9 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) } } else { const char *prop = qdict_get_str(tuple, "name"); - g_test_message("-> %s", prop); + if (verbose) { + g_test_message("-> %s", prop); + } tmp = qtest_qmp(qts, "{ 'execute': 'qom-get'," " 'arguments': { 'path': %s, 'property': %s } }", @@ -103,6 +107,12 @@ static void add_machine_test_case(const char *mname) int main(int argc, char **argv) { + char *v_env = getenv("V"); + + if (v_env && atoi(v_env) >= 2) { + verbose = true; + } + g_test_init(&argc, &argv, NULL); qtest_cb_for_every_machine(add_machine_test_case, g_test_quick()); From 0038e9a22619387a905b57888fb34c5d8ece720e Mon Sep 17 00:00:00 2001 From: Guoyi Tu Date: Mon, 16 Jan 2023 12:56:00 +0800 Subject: [PATCH 052/814] Call qemu_socketpair() instead of socketpair() when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As qemu_socketpair() was introduced in commit 3c63b4e9 ("oslib-posix: Introduce qemu_socketpair()"), it's time to replace the other existing socketpair() calls with qemu_socketpair() if possible Signed-off-by: Guoyi Tu Acked-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Laurent Vivier --- backends/tpm/tpm_emulator.c | 2 +- tests/qtest/dbus-display-test.c | 5 +++-- tests/qtest/migration-test.c | 2 +- tests/unit/test-crypto-tlssession.c | 4 ++-- tests/unit/test-io-channel-tls.c | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 49cc3d749d..67e7b212e3 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -553,7 +553,7 @@ static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu) Error *err = NULL; int fds[2] = { -1, -1 }; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + if (qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { error_report("tpm-emulator: Failed to create socketpair"); return -1; } diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c index cb1b62d1d1..fef025ac6f 100644 --- a/tests/qtest/dbus-display-test.c +++ b/tests/qtest/dbus-display-test.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "qemu/dbus.h" +#include "qemu/sockets.h" #include #include #include "libqtest.h" @@ -36,7 +37,7 @@ test_setup(QTestState **qts, GDBusConnection **conn) *qts = qtest_init("-display dbus,p2p=yes -name dbus-test"); - g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); + g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); qtest_qmp_add_client(*qts, "@dbus-display", pair[1]); @@ -152,7 +153,7 @@ test_dbus_display_console(void) test_setup(&qts, &conn); - g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); + g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); fd_list = g_unix_fd_list_new(); idx = g_unix_fd_list_append(fd_list, pair[1], NULL); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index dbde726adf..1dd32c9506 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -1661,7 +1661,7 @@ static void *test_migrate_fd_start_hook(QTestState *from, int pair[2]; /* Create two connected sockets for migration */ - ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); + ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); g_assert_cmpint(ret, ==, 0); /* Send the 1st socket to the target */ diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c index 615a1344b4..b12e7b6879 100644 --- a/tests/unit/test-crypto-tlssession.c +++ b/tests/unit/test-crypto-tlssession.c @@ -82,7 +82,7 @@ static void test_crypto_tls_session_psk(void) int ret; /* We'll use this for our fake client-server connection */ - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel); + ret = qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel); g_assert(ret == 0); /* @@ -236,7 +236,7 @@ static void test_crypto_tls_session_x509(const void *opaque) int ret; /* We'll use this for our fake client-server connection */ - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel); + ret = qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel); g_assert(ret == 0); /* diff --git a/tests/unit/test-io-channel-tls.c b/tests/unit/test-io-channel-tls.c index cc39247556..e036ac5df4 100644 --- a/tests/unit/test-io-channel-tls.c +++ b/tests/unit/test-io-channel-tls.c @@ -121,7 +121,7 @@ static void test_io_channel_tls(const void *opaque) GMainContext *mainloop; /* We'll use this for our fake client-server connection */ - g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0); + g_assert(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0); #define CLIENT_CERT_DIR "tests/test-io-channel-tls-client/" #define SERVER_CERT_DIR "tests/test-io-channel-tls-server/" From 9815d8839a62603ab2adce58dcc5e4bcc8f9a1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Jan 2023 14:49:22 +0100 Subject: [PATCH 053/814] hw/display: Move omap_lcdc.c out of target-specific source set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While only used by the ARM targets, this device can be built once for all. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209170042.71169-2-philmd@linaro.org> Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-2-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/display/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/meson.build b/hw/display/meson.build index f860c2c562..f470179122 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -115,7 +115,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} endif -specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) +softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-vga-stub.c')) modules += { 'hw-display': hw_display_modules } From d9e2d244c77b3aa4a5ba8ad778019354849e018d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Jan 2023 14:49:23 +0100 Subject: [PATCH 054/814] hw/intc: Move some files out of the target-specific source set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Goldfish interrupt controller is not target specific. While the Exynos interrupt combiner is only used by the ARM targets, we can build this device once for all. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209170042.71169-3-philmd@linaro.org> [thuth: Change patch title, and also move 'exynos4210_gic.c'] Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-3-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/intc/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index cd9f1ee888..0988cae8ab 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -13,6 +13,8 @@ softmmu_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files( 'arm_gicv3_redist.c', )) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c')) +softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c')) +softmmu_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) @@ -39,7 +41,6 @@ specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c')) specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c')) specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c')) specific_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c')) -specific_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c')) specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c')) specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c')) specific_ss.add(when: 'CONFIG_LOONGSON_LIOINTC', if_true: files('loongson_liointc.c')) @@ -66,7 +67,6 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('xics_spapr.c', 'spapr_xi specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) -specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) From ef5c8d0bdf681a843d1b788dc462e5c1404b1580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Jan 2023 14:49:24 +0100 Subject: [PATCH 055/814] hw/tpm: Move tpm_ppi.c out of target-specific source set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPM Physical Presence Interface is not target specific. Build this file once for all targets. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221209170042.71169-4-philmd@linaro.org> [thuth: Drop the CONFIG_SOFTMMU statements, they are not needed here] Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-4-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/tpm/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/tpm/meson.build b/hw/tpm/meson.build index 1c68d81d6a..7abc2d794a 100644 --- a/hw/tpm/meson.build +++ b/hw/tpm/meson.build @@ -2,7 +2,7 @@ softmmu_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_tis_common.c')) softmmu_ss.add(when: 'CONFIG_TPM_TIS_ISA', if_true: files('tpm_tis_isa.c')) softmmu_ss.add(when: 'CONFIG_TPM_TIS_SYSBUS', if_true: files('tpm_tis_sysbus.c')) softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb.c')) +softmmu_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_ppi.c')) +softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_ppi.c')) -specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TPM_TIS'], if_true: files('tpm_ppi.c')) -specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TPM_CRB'], if_true: files('tpm_ppi.c')) specific_ss.add(when: 'CONFIG_TPM_SPAPR', if_true: files('tpm_spapr.c')) From fbdefc85df6db6a15c57733317fd7f7b87d152da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 12 Jan 2023 14:49:25 +0100 Subject: [PATCH 056/814] hw/arm: Move various units to softmmu_ss[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_ss[] units are built twice: once for 32-bit word size and once for 64-bit. The following units don't require any word size knowledge and can be moved to softmmu_ss[] (where they are built once): - smmu-common.c - exynos4_boards.c - bcm2835_peripherals.c - tosa.c Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230110164406.94366-2-philmd@linaro.org> Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-5-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/arm/meson.build | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 76d4d650e4..b036045603 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -3,7 +3,6 @@ arm_ss.add(files('boot.c'), fdt) 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_EXYNOS4', if_true: files('exynos4_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')) @@ -19,7 +18,6 @@ arm_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) arm_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c')) arm_ss.add(when: 'CONFIG_GUMSTIX', if_true: files('gumstix.c')) arm_ss.add(when: 'CONFIG_SPITZ', if_true: files('spitz.c')) -arm_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c')) arm_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c')) arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c')) arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c')) @@ -39,7 +37,7 @@ arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c', 'omap2.c')) arm_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.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_RASPI', if_true: files('bcm2835_peripherals.c', 'bcm2836.c', 'raspi.c')) +arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.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')) @@ -60,8 +58,13 @@ 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_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.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')) +softmmu_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) +softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c')) +softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c')) +softmmu_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c')) + hw_arch += {'arm': arm_ss} From fb73eec46bdbfad0977b9a46f102a53e9083599c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Jan 2023 14:49:26 +0100 Subject: [PATCH 057/814] hw/cpu: Mark arm11 and realview mpcore as target-independent code Seems like there is nothing target-specific in here, so these files can be moved to softmmu_ss to avoid that they get compiled twice (once for qemu-system-arm and once for qemu-system-aarch64). Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-6-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/cpu/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/cpu/meson.build b/hw/cpu/meson.build index 9e52fee9e7..e37490074f 100644 --- a/hw/cpu/meson.build +++ b/hw/cpu/meson.build @@ -1,6 +1,6 @@ softmmu_ss.add(files('core.c', 'cluster.c')) -specific_ss.add(when: 'CONFIG_ARM11MPCORE', if_true: files('arm11mpcore.c')) -specific_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_mpcore.c')) +softmmu_ss.add(when: 'CONFIG_ARM11MPCORE', if_true: files('arm11mpcore.c')) +softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_mpcore.c')) specific_ss.add(when: 'CONFIG_A9MPCORE', if_true: files('a9mpcore.c')) specific_ss.add(when: 'CONFIG_A15MPCORE', if_true: files('a15mpcore.c')) From 550174d629e505f087124ebcb935c83fc205fdc7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Jan 2023 14:49:27 +0100 Subject: [PATCH 058/814] hw/intc: Mark more interrupt-controller files as target independent Seems like there is also nothing target-specific in here, so these files can be moved to softmmu_ss to avoid that they get compiled twice (once for qemu-system-arm and once for qemu-system-aarch64). Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-7-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/intc/meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 0988cae8ab..8be459b41c 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -12,6 +12,8 @@ softmmu_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files( 'arm_gicv3_its.c', 'arm_gicv3_redist.c', )) +softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c')) +softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c')) softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c')) softmmu_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) @@ -19,8 +21,10 @@ softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c')) +softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c')) softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c')) softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c')) +softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c')) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c')) @@ -33,25 +37,21 @@ if config_all_devices.has_key('CONFIG_APIC') or \ softmmu_ss.add(files('kvm_irqcount.c')) endif -specific_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c')) specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c')) specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c')) specific_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files('arm_gicv3_cpuif.c')) specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c')) specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c')) specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c')) -specific_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c')) specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c')) specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c')) specific_ss.add(when: 'CONFIG_LOONGSON_LIOINTC', if_true: files('loongson_liointc.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gic.c')) -specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c')) specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_OPENPIC'], if_true: files('openpic_kvm.c')) specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c', 'pnv_xive2.c')) specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c')) -specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c')) specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c')) specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c')) specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c')) From a48f692929828212f75eb6e8d11bbb6cdffad153 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Jan 2023 14:49:28 +0100 Subject: [PATCH 059/814] hw/usb: Mark the XLNX_VERSAL-related files as target-independent Seems like there is nothing target-specific in here, so these files can be moved to softmmu_ss to avoid that they get compiled twice (once for qemu-system-arm and once for qemu-system-aarch64). Signed-off-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230112134928.1026006-8-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/usb/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/meson.build b/hw/usb/meson.build index 793df42e21..bdf34cbd3e 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -30,8 +30,8 @@ softmmu_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c')) softmmu_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c')) softmmu_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c')) -specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c')) -specific_ss.add(when: 'CONFIG_XLNX_USB_SUBSYS', if_true: files('xlnx-usb-subsystem.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_USB_SUBSYS', if_true: files('xlnx-usb-subsystem.c')) # emulated usb devices softmmu_ss.add(when: 'CONFIG_USB', if_true: files('dev-hub.c')) From 6eb71c6a1e917f3a6ece71593ff44de6eae8bba9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 9 Jan 2023 11:13:06 +0100 Subject: [PATCH 060/814] tests/qtest/test-hmp: Improve the check for verbose mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running the test-hmp with V=2 up to V=9 runs the test in verbose mode, but running for example with V=10 falls back to non-verbose mode ... Improve this oddity by properly treating the argument as a number. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109101306.271444-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- tests/qtest/test-hmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/test-hmp.c b/tests/qtest/test-hmp.c index f8b22abe4c..b4a920df89 100644 --- a/tests/qtest/test-hmp.c +++ b/tests/qtest/test-hmp.c @@ -151,7 +151,7 @@ int main(int argc, char **argv) { char *v_env = getenv("V"); - if (v_env && *v_env >= '2') { + if (v_env && atoi(v_env) >= 2) { verbose = true; } From 09aa7be196ebd94d68dc06c62fdcea040e2bd196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Jan 2023 18:38:26 +0100 Subject: [PATCH 061/814] hw/i386/pc: Remove unused 'owner' argument from pc_pci_as_mapping_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This argument was added 9 years ago in commit 83d08f2673 ("pc: map PCI address space as catchall region for not mapped addresses") and has never been used since, so remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Message-Id: <20230105173826.56748-1-philmd@linaro.org> Signed-off-by: Laurent Vivier --- hw/i386/pc.c | 2 +- hw/pci-host/i440fx.c | 3 +-- hw/pci-host/q35.c | 3 +-- include/hw/i386/pc.h | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d489ecc0d1..6e592bd969 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -782,7 +782,7 @@ void pc_guest_info_init(PCMachineState *pcms) } /* setup pci memory address space mapping into system address space */ -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, +void pc_pci_as_mapping_init(MemoryRegion *system_memory, MemoryRegion *pci_address_space) { /* Set to lower priority than RAM */ diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index d5426ef4a5..262f82c303 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -272,8 +272,7 @@ PCIBus *i440fx_init(const char *pci_type, IO_APIC_DEFAULT_ADDRESS - 1); /* setup pci memory mapping */ - pc_pci_as_mapping_init(OBJECT(f), f->system_memory, - f->pci_address_space); + pc_pci_as_mapping_init(f->system_memory, f->pci_address_space); /* if *disabled* show SMRAM to all CPUs */ memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region", diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 20da121374..26390863d6 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -574,8 +574,7 @@ static void mch_realize(PCIDevice *d, Error **errp) } /* setup pci memory mapping */ - pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory, - mch->pci_address_space); + pc_pci_as_mapping_init(mch->system_memory, mch->pci_address_space); /* if *disabled* show SMRAM to all CPUs */ memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region", diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 991f905f5d..88a120bc23 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -156,7 +156,7 @@ void pc_guest_info_init(PCMachineState *pcms); #define PCI_HOST_ABOVE_4G_MEM_SIZE "above-4g-mem-size" -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, +void pc_pci_as_mapping_init(MemoryRegion *system_memory, MemoryRegion *pci_address_space); void xen_load_linux(PCMachineState *pcms); From daa500cab6a4f8fdaa1a0689a5d39a6b67213801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 3 Jan 2023 15:08:05 +0400 Subject: [PATCH 062/814] ccid-card-emulated: fix cast warning/error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../hw/usb/ccid-card-emulated.c: In function 'handle_apdu_thread': ../hw/usb/ccid-card-emulated.c:251:24: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] 251 | assert((unsigned long)event > 1000); Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth Message-Id: <20230103110814.3726795-2-marcandre.lureau@redhat.com> Signed-off-by: Laurent Vivier --- hw/usb/ccid-card-emulated.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index ee41a81801..c328660075 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -248,7 +248,7 @@ static void *handle_apdu_thread(void* arg) WITH_QEMU_LOCK_GUARD(&card->vreader_mutex) { while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) { event = QSIMPLEQ_FIRST(&card->guest_apdu_list); - assert((unsigned long)event > 1000); + assert(event != NULL); QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry); if (event->p.data.type != EMUL_GUEST_APDU) { DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n"); From 31c4b6fb0293e359f9ef8a61892667e76eea4c99 Mon Sep 17 00:00:00 2001 From: Yuval Shaia Date: Sun, 3 Apr 2022 12:52:34 +0300 Subject: [PATCH 063/814] hw/pvrdma: Protect against buggy or malicious guest driver Guest driver might execute HW commands when shared buffers are not yet allocated. This could happen on purpose (malicious guest) or because of some other guest/host address mapping error. We need to protect againts such case. Fixes: CVE-2022-1050 Reported-by: Raven Signed-off-by: Yuval Shaia Message-Id: <20220403095234.2210-1-yuval.shaia.ml@gmail.com> Signed-off-by: Laurent Vivier --- hw/rdma/vmw/pvrdma_cmd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c index 1eca6328c9..c6ed025982 100644 --- a/hw/rdma/vmw/pvrdma_cmd.c +++ b/hw/rdma/vmw/pvrdma_cmd.c @@ -776,6 +776,12 @@ int pvrdma_exec_cmd(PVRDMADev *dev) dsr_info = &dev->dsr_info; + if (!dsr_info->dsr) { + /* Buggy or malicious guest driver */ + rdma_error_report("Exec command without dsr, req or rsp buffers"); + goto out; + } + if (dsr_info->req->hdr.cmd >= sizeof(cmd_handlers) / sizeof(struct cmd_handler)) { rdma_error_report("Unsupported command"); From f0376c3f0fc37912d068ab26fc24af77c60d6e77 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Thu, 15 Dec 2022 15:37:49 +0300 Subject: [PATCH 064/814] hw/cxl/cxl-cdat.c: spelling: missmatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced by: aba578bdace5303a441f8a37aad781b5cb06f38c Signed-off-by: Michael Tokarev Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20221215123749.1026775-1-mjt@msgid.tls.msk.ru> Signed-off-by: Laurent Vivier --- hw/cxl/cxl-cdat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c index 3653aa56f0..137abd0992 100644 --- a/hw/cxl/cxl-cdat.c +++ b/hw/cxl/cxl-cdat.c @@ -146,7 +146,7 @@ static void ct3_load_cdat(CDATObject *cdat, Error **errp) num_ent++; } if (i != file_size) { - error_setg(errp, "CDAT: File length missmatch"); + error_setg(errp, "CDAT: File length mismatch"); return; } From da91c19202420d61e3316f5a9d4c2d66bfbaff04 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 12 Jan 2023 16:20:11 +0100 Subject: [PATCH 065/814] linux-user: Clean up when exiting due to a signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When exiting due to an exit() syscall, qemu-user calls preexit_cleanup(), but this is currently not the case when exiting due to a signal. This leads to various buffers not being flushed (e.g., for gprof, for gcov, and for the upcoming perf support). Add the missing call. Signed-off-by: Ilya Leoshkevich Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20230112152013.125680-2-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- linux-user/signal.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 61c6fa3fcf..098f3a787d 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -695,7 +695,7 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, /* abort execution with signal */ static G_NORETURN -void dump_core_and_abort(int target_sig) +void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) { CPUState *cpu = thread_cpu; CPUArchState *env = cpu->env_ptr; @@ -724,6 +724,8 @@ void dump_core_and_abort(int target_sig) target_sig, strsignal(host_sig), "core dumped" ); } + preexit_cleanup(cpu_env, 128 + target_sig); + /* The proper exit code for dying from an uncaught signal is * -. The kernel doesn't allow exit() or _exit() to pass * a negative value. To get the proper exit code we need to @@ -1058,12 +1060,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH && sig != TARGET_SIGCONT) { - dump_core_and_abort(sig); + dump_core_and_abort(cpu_env, sig); } } else if (handler == TARGET_SIG_IGN) { /* ignore sig */ } else if (handler == TARGET_SIG_ERR) { - dump_core_and_abort(sig); + dump_core_and_abort(cpu_env, sig); } else { /* compute the blocked signals during the handler execution */ sigset_t *blocked_set; From 7c10cb38ccb86a0e56fff32bb348aa4b34e17e10 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 12 Jan 2023 16:20:12 +0100 Subject: [PATCH 066/814] accel/tcg: Add debuginfo support Add libdw-based functions for loading and querying debuginfo. Load debuginfo from the system and the linux-user loaders. This is useful for the upcoming perf support, which can then put human-readable guest symbols instead of raw guest PCs into perfmap and jitdump files. Signed-off-by: Ilya Leoshkevich Message-Id: <20230112152013.125680-3-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- accel/tcg/debuginfo.c | 96 ++++++++++++++++++++++++++++++++++++++++++ accel/tcg/debuginfo.h | 77 +++++++++++++++++++++++++++++++++ accel/tcg/meson.build | 1 + hw/core/loader.c | 5 +++ linux-user/elfload.c | 3 ++ linux-user/meson.build | 1 + meson.build | 8 ++++ 7 files changed, 191 insertions(+) create mode 100644 accel/tcg/debuginfo.c create mode 100644 accel/tcg/debuginfo.h diff --git a/accel/tcg/debuginfo.c b/accel/tcg/debuginfo.c new file mode 100644 index 0000000000..71c66d04d1 --- /dev/null +++ b/accel/tcg/debuginfo.c @@ -0,0 +1,96 @@ +/* + * Debug information support. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/lockable.h" + +#include + +#include "debuginfo.h" + +static QemuMutex lock; +static Dwfl *dwfl; +static const Dwfl_Callbacks dwfl_callbacks = { + .find_elf = NULL, + .find_debuginfo = dwfl_standard_find_debuginfo, + .section_address = NULL, + .debuginfo_path = NULL, +}; + +__attribute__((constructor)) +static void debuginfo_init(void) +{ + qemu_mutex_init(&lock); +} + +void debuginfo_report_elf(const char *name, int fd, uint64_t bias) +{ + QEMU_LOCK_GUARD(&lock); + + if (dwfl) { + dwfl_report_begin_add(dwfl); + } else { + dwfl = dwfl_begin(&dwfl_callbacks); + } + + if (dwfl) { + dwfl_report_elf(dwfl, name, name, fd, bias, true); + dwfl_report_end(dwfl, NULL, NULL); + } +} + +void debuginfo_lock(void) +{ + qemu_mutex_lock(&lock); +} + +void debuginfo_query(struct debuginfo_query *q, size_t n) +{ + const char *symbol, *file; + Dwfl_Module *dwfl_module; + Dwfl_Line *dwfl_line; + GElf_Off dwfl_offset; + GElf_Sym dwfl_sym; + size_t i; + int line; + + if (!dwfl) { + return; + } + + for (i = 0; i < n; i++) { + dwfl_module = dwfl_addrmodule(dwfl, q[i].address); + if (!dwfl_module) { + continue; + } + + if (q[i].flags & DEBUGINFO_SYMBOL) { + symbol = dwfl_module_addrinfo(dwfl_module, q[i].address, + &dwfl_offset, &dwfl_sym, + NULL, NULL, NULL); + if (symbol) { + q[i].symbol = symbol; + q[i].offset = dwfl_offset; + } + } + + if (q[i].flags & DEBUGINFO_LINE) { + dwfl_line = dwfl_module_getsrc(dwfl_module, q[i].address); + if (dwfl_line) { + file = dwfl_lineinfo(dwfl_line, NULL, &line, 0, NULL, NULL); + if (file) { + q[i].file = file; + q[i].line = line; + } + } + } + } +} + +void debuginfo_unlock(void) +{ + qemu_mutex_unlock(&lock); +} diff --git a/accel/tcg/debuginfo.h b/accel/tcg/debuginfo.h new file mode 100644 index 0000000000..7542cfe6e0 --- /dev/null +++ b/accel/tcg/debuginfo.h @@ -0,0 +1,77 @@ +/* + * Debug information support. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ACCEL_TCG_DEBUGINFO_H +#define ACCEL_TCG_DEBUGINFO_H + +/* + * Debuginfo describing a certain address. + */ +struct debuginfo_query { + uint64_t address; /* Input: address. */ + int flags; /* Input: debuginfo subset. */ + const char *symbol; /* Symbol that the address is part of. */ + uint64_t offset; /* Offset from the symbol. */ + const char *file; /* Source file associated with the address. */ + int line; /* Line number in the source file. */ +}; + +/* + * Debuginfo subsets. + */ +#define DEBUGINFO_SYMBOL BIT(1) +#define DEBUGINFO_LINE BIT(2) + +#if defined(CONFIG_TCG) && defined(CONFIG_LIBDW) +/* + * Load debuginfo for the specified guest ELF image. + * Return true on success, false on failure. + */ +void debuginfo_report_elf(const char *name, int fd, uint64_t bias); + +/* + * Take the debuginfo lock. + */ +void debuginfo_lock(void); + +/* + * Fill each on N Qs with the debuginfo about Q->ADDRESS as specified by + * Q->FLAGS: + * + * - DEBUGINFO_SYMBOL: update Q->SYMBOL and Q->OFFSET. If symbol debuginfo is + * missing, then leave them as is. + * - DEBUINFO_LINE: update Q->FILE and Q->LINE. If line debuginfo is missing, + * then leave them as is. + * + * This function must be called under the debuginfo lock. The results can be + * accessed only until the debuginfo lock is released. + */ +void debuginfo_query(struct debuginfo_query *q, size_t n); + +/* + * Release the debuginfo lock. + */ +void debuginfo_unlock(void); +#else +static inline void debuginfo_report_elf(const char *image_name, int image_fd, + uint64_t load_bias) +{ +} + +static inline void debuginfo_lock(void) +{ +} + +static inline void debuginfo_query(struct debuginfo_query *q, size_t n) +{ +} + +static inline void debuginfo_unlock(void) +{ +} +#endif + +#endif diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 75e1dffb4d..55b3b4dd7e 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -12,6 +12,7 @@ tcg_ss.add(files( tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c')) tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')]) +tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files( diff --git a/hw/core/loader.c b/hw/core/loader.c index 0548830733..55dbe2e199 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -61,6 +61,7 @@ #include "hw/boards.h" #include "qemu/cutils.h" #include "sysemu/runstate.h" +#include "accel/tcg/debuginfo.h" #include @@ -503,6 +504,10 @@ ssize_t load_elf_ram_sym(const char *filename, clear_lsb, data_swab, as, load_rom, sym_cb); } + if (ret != ELF_LOAD_FAILED) { + debuginfo_report_elf(filename, fd, 0); + } + fail: close(fd); return ret; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 20894b633f..5928c14dfc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -19,6 +19,7 @@ #include "qemu/selfmap.h" #include "qapi/error.h" #include "target_signal.h" +#include "accel/tcg/debuginfo.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -3261,6 +3262,8 @@ static void load_elf_image(const char *image_name, int image_fd, load_symbols(ehdr, image_fd, load_bias); } + debuginfo_report_elf(image_name, image_fd, load_bias); + mmap_unlock(); close(image_fd); diff --git a/linux-user/meson.build b/linux-user/meson.build index de4320af05..7171dc60be 100644 --- a/linux-user/meson.build +++ b/linux-user/meson.build @@ -22,6 +22,7 @@ linux_user_ss.add(files( 'uname.c', )) linux_user_ss.add(rt) +linux_user_ss.add(libdw) linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c')) linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c')) diff --git a/meson.build b/meson.build index 5d68a8fd23..6d212f6c8e 100644 --- a/meson.build +++ b/meson.build @@ -1648,6 +1648,12 @@ if libbpf.found() and not cc.links(''' endif endif +# libdw +libdw = dependency('libdw', + method: 'pkg-config', + kwargs: static_kwargs, + required: false) + ################# # config-host.h # ################# @@ -1923,6 +1929,7 @@ config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display) config_host_data.set('CONFIG_CFI', get_option('cfi')) config_host_data.set('CONFIG_SELINUX', selinux.found()) config_host_data.set('CONFIG_XEN_BACKEND', xen.found()) +config_host_data.set('CONFIG_LIBDW', libdw.found()) if xen.found() # protect from xen.version() having less than three components xen_version = xen.version().split('.') + ['0', '0'] @@ -3976,6 +3983,7 @@ summary_info += {'libudev': libudev} # Dummy dependency, keep .found() summary_info += {'FUSE lseek': fuse_lseek.found()} summary_info += {'selinux': selinux} +summary_info += {'libdw': libdw} summary(summary_info, bool_yn: true, section: 'Dependencies') if not supported_cpus.contains(cpu) From 5584e2dbe8c9c95ceb178786fb88e5edf625e1b6 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 12 Jan 2023 16:20:13 +0100 Subject: [PATCH 067/814] tcg: add perfmap and jitdump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ability to dump /tmp/perf-.map and jit-.dump. The first one allows the perf tool to map samples to each individual translation block. The second one adds the ability to resolve symbol names, line numbers and inspect JITed code. Example of use: perf record qemu-x86_64 -perfmap ./a.out perf report or perf record -k 1 qemu-x86_64 -jitdump ./a.out DEBUGINFOD_URLS= perf inject -j -i perf.data -o perf.data.jitted perf report -i perf.data.jitted Co-developed-by: Vanderson M. do Rosario Co-developed-by: Alex Bennée Signed-off-by: Ilya Leoshkevich Message-Id: <20230112152013.125680-4-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 1 + accel/tcg/perf.c | 375 ++++++++++++++++++++++++++++++++++++++ accel/tcg/perf.h | 49 +++++ accel/tcg/translate-all.c | 7 + docs/devel/tcg.rst | 23 +++ linux-user/exit.c | 2 + linux-user/main.c | 15 ++ qemu-options.hx | 20 ++ softmmu/vl.c | 11 ++ tcg/tcg.c | 2 + 10 files changed, 505 insertions(+) create mode 100644 accel/tcg/perf.c create mode 100644 accel/tcg/perf.h diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 55b3b4dd7e..77740b1a0d 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -13,6 +13,7 @@ tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c')) tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')]) tcg_ss.add(when: libdw, if_true: files('debuginfo.c')) +tcg_ss.add(when: 'CONFIG_LINUX', if_true: files('perf.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files( diff --git a/accel/tcg/perf.c b/accel/tcg/perf.c new file mode 100644 index 0000000000..ae19f6e28f --- /dev/null +++ b/accel/tcg/perf.c @@ -0,0 +1,375 @@ +/* + * Linux perf perf-.map and jit-.dump integration. + * + * The jitdump spec can be found at [1]. + * + * [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/perf/Documentation/jitdump-specification.txt + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "elf.h" +#include "exec/exec-all.h" +#include "qemu/timer.h" +#include "tcg/tcg.h" + +#include "debuginfo.h" +#include "perf.h" + +static FILE *safe_fopen_w(const char *path) +{ + int saved_errno; + FILE *f; + int fd; + + /* Delete the old file, if any. */ + unlink(path); + + /* Avoid symlink attacks by using O_CREAT | O_EXCL. */ + fd = open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd == -1) { + return NULL; + } + + /* Convert fd to FILE*. */ + f = fdopen(fd, "w"); + if (f == NULL) { + saved_errno = errno; + close(fd); + errno = saved_errno; + return NULL; + } + + return f; +} + +static FILE *perfmap; + +void perf_enable_perfmap(void) +{ + char map_file[32]; + + snprintf(map_file, sizeof(map_file), "/tmp/perf-%d.map", getpid()); + perfmap = safe_fopen_w(map_file); + if (perfmap == NULL) { + warn_report("Could not open %s: %s, proceeding without perfmap", + map_file, strerror(errno)); + } +} + +/* Get PC and size of code JITed for guest instruction #INSN. */ +static void get_host_pc_size(uintptr_t *host_pc, uint16_t *host_size, + const void *start, size_t insn) +{ + uint16_t start_off = insn ? tcg_ctx->gen_insn_end_off[insn - 1] : 0; + + if (host_pc) { + *host_pc = (uintptr_t)start + start_off; + } + if (host_size) { + *host_size = tcg_ctx->gen_insn_end_off[insn] - start_off; + } +} + +static const char *pretty_symbol(const struct debuginfo_query *q, size_t *len) +{ + static __thread char buf[64]; + int tmp; + + if (!q->symbol) { + tmp = snprintf(buf, sizeof(buf), "guest-0x%"PRIx64, q->address); + if (len) { + *len = MIN(tmp + 1, sizeof(buf)); + } + return buf; + } + + if (!q->offset) { + if (len) { + *len = strlen(q->symbol) + 1; + } + return q->symbol; + } + + tmp = snprintf(buf, sizeof(buf), "%s+0x%"PRIx64, q->symbol, q->offset); + if (len) { + *len = MIN(tmp + 1, sizeof(buf)); + } + return buf; +} + +static void write_perfmap_entry(const void *start, size_t insn, + const struct debuginfo_query *q) +{ + uint16_t host_size; + uintptr_t host_pc; + + get_host_pc_size(&host_pc, &host_size, start, insn); + fprintf(perfmap, "%"PRIxPTR" %"PRIx16" %s\n", + host_pc, host_size, pretty_symbol(q, NULL)); +} + +static FILE *jitdump; + +#define JITHEADER_MAGIC 0x4A695444 +#define JITHEADER_VERSION 1 + +struct jitheader { + uint32_t magic; + uint32_t version; + uint32_t total_size; + uint32_t elf_mach; + uint32_t pad1; + uint32_t pid; + uint64_t timestamp; + uint64_t flags; +}; + +enum jit_record_type { + JIT_CODE_LOAD = 0, + JIT_CODE_DEBUG_INFO = 2, +}; + +struct jr_prefix { + uint32_t id; + uint32_t total_size; + uint64_t timestamp; +}; + +struct jr_code_load { + struct jr_prefix p; + + uint32_t pid; + uint32_t tid; + uint64_t vma; + uint64_t code_addr; + uint64_t code_size; + uint64_t code_index; +}; + +struct debug_entry { + uint64_t addr; + int lineno; + int discrim; + const char name[]; +}; + +struct jr_code_debug_info { + struct jr_prefix p; + + uint64_t code_addr; + uint64_t nr_entry; + struct debug_entry entries[]; +}; + +static uint32_t get_e_machine(void) +{ + Elf64_Ehdr elf_header; + FILE *exe; + size_t n; + + QEMU_BUILD_BUG_ON(offsetof(Elf32_Ehdr, e_machine) != + offsetof(Elf64_Ehdr, e_machine)); + + exe = fopen("/proc/self/exe", "r"); + if (exe == NULL) { + return EM_NONE; + } + + n = fread(&elf_header, sizeof(elf_header), 1, exe); + fclose(exe); + if (n != 1) { + return EM_NONE; + } + + return elf_header.e_machine; +} + +void perf_enable_jitdump(void) +{ + struct jitheader header; + char jitdump_file[32]; + void *perf_marker; + + if (!use_rt_clock) { + warn_report("CLOCK_MONOTONIC is not available, proceeding without jitdump"); + return; + } + + snprintf(jitdump_file, sizeof(jitdump_file), "jit-%d.dump", getpid()); + jitdump = safe_fopen_w(jitdump_file); + if (jitdump == NULL) { + warn_report("Could not open %s: %s, proceeding without jitdump", + jitdump_file, strerror(errno)); + return; + } + + /* + * `perf inject` will see that the mapped file name in the corresponding + * PERF_RECORD_MMAP or PERF_RECORD_MMAP2 event is of the form jit-%d.dump + * and will process it as a jitdump file. + */ + perf_marker = mmap(NULL, qemu_real_host_page_size(), PROT_READ | PROT_EXEC, + MAP_PRIVATE, fileno(jitdump), 0); + if (perf_marker == MAP_FAILED) { + warn_report("Could not map %s: %s, proceeding without jitdump", + jitdump_file, strerror(errno)); + fclose(jitdump); + jitdump = NULL; + return; + } + + header.magic = JITHEADER_MAGIC; + header.version = JITHEADER_VERSION; + header.total_size = sizeof(header); + header.elf_mach = get_e_machine(); + header.pad1 = 0; + header.pid = getpid(); + header.timestamp = get_clock(); + header.flags = 0; + fwrite(&header, sizeof(header), 1, jitdump); +} + +void perf_report_prologue(const void *start, size_t size) +{ + if (perfmap) { + fprintf(perfmap, "%"PRIxPTR" %zx tcg-prologue-buffer\n", + (uintptr_t)start, size); + } +} + +/* Write a JIT_CODE_DEBUG_INFO jitdump entry. */ +static void write_jr_code_debug_info(const void *start, + const struct debuginfo_query *q, + size_t icount) +{ + struct jr_code_debug_info rec; + struct debug_entry ent; + uintptr_t host_pc; + int insn; + + /* Write the header. */ + rec.p.id = JIT_CODE_DEBUG_INFO; + rec.p.total_size = sizeof(rec) + sizeof(ent) + 1; + rec.p.timestamp = get_clock(); + rec.code_addr = (uintptr_t)start; + rec.nr_entry = 1; + for (insn = 0; insn < icount; insn++) { + if (q[insn].file) { + rec.p.total_size += sizeof(ent) + strlen(q[insn].file) + 1; + rec.nr_entry++; + } + } + fwrite(&rec, sizeof(rec), 1, jitdump); + + /* Write the main debug entries. */ + for (insn = 0; insn < icount; insn++) { + if (q[insn].file) { + get_host_pc_size(&host_pc, NULL, start, insn); + ent.addr = host_pc; + ent.lineno = q[insn].line; + ent.discrim = 0; + fwrite(&ent, sizeof(ent), 1, jitdump); + fwrite(q[insn].file, strlen(q[insn].file) + 1, 1, jitdump); + } + } + + /* Write the trailing debug_entry. */ + ent.addr = (uintptr_t)start + tcg_ctx->gen_insn_end_off[icount - 1]; + ent.lineno = 0; + ent.discrim = 0; + fwrite(&ent, sizeof(ent), 1, jitdump); + fwrite("", 1, 1, jitdump); +} + +/* Write a JIT_CODE_LOAD jitdump entry. */ +static void write_jr_code_load(const void *start, uint16_t host_size, + const struct debuginfo_query *q) +{ + static uint64_t code_index; + struct jr_code_load rec; + const char *symbol; + size_t symbol_size; + + symbol = pretty_symbol(q, &symbol_size); + rec.p.id = JIT_CODE_LOAD; + rec.p.total_size = sizeof(rec) + symbol_size + host_size; + rec.p.timestamp = get_clock(); + rec.pid = getpid(); + rec.tid = qemu_get_thread_id(); + rec.vma = (uintptr_t)start; + rec.code_addr = (uintptr_t)start; + rec.code_size = host_size; + rec.code_index = code_index++; + fwrite(&rec, sizeof(rec), 1, jitdump); + fwrite(symbol, symbol_size, 1, jitdump); + fwrite(start, host_size, 1, jitdump); +} + +void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, + const void *start) +{ + struct debuginfo_query *q; + size_t insn; + + if (!perfmap && !jitdump) { + return; + } + + q = g_try_malloc0_n(tb->icount, sizeof(*q)); + if (!q) { + return; + } + + debuginfo_lock(); + + /* Query debuginfo for each guest instruction. */ + for (insn = 0; insn < tb->icount; insn++) { + /* FIXME: This replicates the restore_state_to_opc() logic. */ + q[insn].address = tcg_ctx->gen_insn_data[insn][0]; + if (TARGET_TB_PCREL) { + q[insn].address |= (guest_pc & TARGET_PAGE_MASK); + } else { +#if defined(TARGET_I386) + q[insn].address -= tb->cs_base; +#endif + } + q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0); + } + debuginfo_query(q, tb->icount); + + /* Emit perfmap entries if needed. */ + if (perfmap) { + flockfile(perfmap); + for (insn = 0; insn < tb->icount; insn++) { + write_perfmap_entry(start, insn, &q[insn]); + } + funlockfile(perfmap); + } + + /* Emit jitdump entries if needed. */ + if (jitdump) { + flockfile(jitdump); + write_jr_code_debug_info(start, q, tb->icount); + write_jr_code_load(start, tcg_ctx->gen_insn_end_off[tb->icount - 1], + q); + funlockfile(jitdump); + } + + debuginfo_unlock(); + g_free(q); +} + +void perf_exit(void) +{ + if (perfmap) { + fclose(perfmap); + perfmap = NULL; + } + + if (jitdump) { + fclose(jitdump); + jitdump = NULL; + } +} diff --git a/accel/tcg/perf.h b/accel/tcg/perf.h new file mode 100644 index 0000000000..f92dd52c69 --- /dev/null +++ b/accel/tcg/perf.h @@ -0,0 +1,49 @@ +/* + * Linux perf perf-.map and jit-.dump integration. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ACCEL_TCG_PERF_H +#define ACCEL_TCG_PERF_H + +#if defined(CONFIG_TCG) && defined(CONFIG_LINUX) +/* Start writing perf-.map. */ +void perf_enable_perfmap(void); + +/* Start writing jit-.dump. */ +void perf_enable_jitdump(void); + +/* Add information about TCG prologue to profiler maps. */ +void perf_report_prologue(const void *start, size_t size); + +/* Add information about JITted guest code to profiler maps. */ +void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, + const void *start); + +/* Stop writing perf-.map and/or jit-.dump. */ +void perf_exit(void); +#else +static inline void perf_enable_perfmap(void) +{ +} + +static inline void perf_enable_jitdump(void) +{ +} + +static inline void perf_report_prologue(const void *start, size_t size) +{ +} + +static inline void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, + const void *start) +{ +} + +static inline void perf_exit(void) +{ +} +#endif + +#endif diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 51ac1f6c84..979f8e1107 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -62,6 +62,7 @@ #include "tb-hash.h" #include "tb-context.h" #include "internal.h" +#include "perf.h" /* Make sure all possible CPU event bits fit in tb->trace_vcpu_dstate */ QEMU_BUILD_BUG_ON(CPU_TRACE_DSTATE_MAX_EVENTS > @@ -406,6 +407,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu, } tb->tc.size = gen_code_size; + /* + * For TARGET_TB_PCREL, attribute all executions of the generated + * code to its first mapping. + */ + perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf)); + #ifdef CONFIG_PROFILER qatomic_set(&prof->code_time, prof->code_time + profile_getclock() - ti); qatomic_set(&prof->code_in_len, prof->code_in_len + tb->size); diff --git a/docs/devel/tcg.rst b/docs/devel/tcg.rst index 136a7a0d96..b4096a17df 100644 --- a/docs/devel/tcg.rst +++ b/docs/devel/tcg.rst @@ -188,3 +188,26 @@ memory areas instead calls out to C code for device emulation. Finally, the MMU helps tracking dirty pages and pages pointed to by translation blocks. +Profiling JITted code +--------------------- + +The Linux ``perf`` tool will treat all JITted code as a single block as +unlike the main code it can't use debug information to link individual +program counter samples with larger functions. To overcome this +limitation you can use the ``-perfmap`` or the ``-jitdump`` option to generate +map files. ``-perfmap`` is lightweight and produces only guest-host mappings. +``-jitdump`` additionally saves JITed code and guest debug information (if +available); its output needs to be integrated with the ``perf.data`` file +before the final report can be viewed. + +.. code:: + + perf record $QEMU -perfmap $REMAINING_ARGS + perf report + + perf record -k 1 $QEMU -jitdump $REMAINING_ARGS + DEBUGINFOD_URLS= perf inject -j -i perf.data -o perf.data.jitted + perf report -i perf.data.jitted + +Note that qemu-system generates mappings only for ``-kernel`` files in ELF +format. diff --git a/linux-user/exit.c b/linux-user/exit.c index fa6ef0b9b4..607b6da9fc 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ #include "qemu/osdep.h" +#include "accel/tcg/perf.h" #include "exec/gdbstub.h" #include "qemu.h" #include "user-internals.h" @@ -38,4 +39,5 @@ void preexit_cleanup(CPUArchState *env, int code) #endif gdb_exit(code); qemu_plugin_user_exit(); + perf_exit(); } diff --git a/linux-user/main.c b/linux-user/main.c index a17fed045b..4290651c3c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -53,6 +53,7 @@ #include "signal-common.h" #include "loader.h" #include "user-mmap.h" +#include "accel/tcg/perf.h" #ifdef CONFIG_SEMIHOSTING #include "semihosting/semihost.h" @@ -423,6 +424,16 @@ static void handle_arg_abi_call0(const char *arg) } #endif +static void handle_arg_perfmap(const char *arg) +{ + perf_enable_perfmap(); +} + +static void handle_arg_jitdump(const char *arg) +{ + perf_enable_jitdump(); +} + static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins); #ifdef CONFIG_PLUGIN @@ -493,6 +504,10 @@ static const struct qemu_argument arg_table[] = { {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0, "", "assume CALL0 Xtensa ABI"}, #endif + {"perfmap", "QEMU_PERFMAP", false, handle_arg_perfmap, + "", "Generate a /tmp/perf-${pid}.map file for perf"}, + {"jitdump", "QEMU_JITDUMP", false, handle_arg_jitdump, + "", "Generate a jit-${pid}.dump file for perf"}, {NULL, NULL, false, NULL, NULL, NULL} }; diff --git a/qemu-options.hx b/qemu-options.hx index 3aa3a2f5a3..d59d19704b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4838,6 +4838,26 @@ SRST Enable synchronization profiling. ERST +#if defined(CONFIG_TCG) && defined(CONFIG_LINUX) +DEF("perfmap", 0, QEMU_OPTION_perfmap, + "-perfmap generate a /tmp/perf-${pid}.map file for perf\n", + QEMU_ARCH_ALL) +SRST +``-perfmap`` + Generate a map file for Linux perf tools that will allow basic profiling + information to be broken down into basic blocks. +ERST + +DEF("jitdump", 0, QEMU_OPTION_jitdump, + "-jitdump generate a jit-${pid}.dump file for perf\n", + QEMU_ARCH_ALL) +SRST +``-jitdump`` + Generate a dump file for Linux perf tools that maps basic blocks to symbol + names, line numbers and JITted code. +ERST +#endif + DEFHEADING() DEFHEADING(Generic object creation:) diff --git a/softmmu/vl.c b/softmmu/vl.c index 9bd0e52d01..9177d95d4e 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -96,6 +96,9 @@ #include "fsdev/qemu-fsdev.h" #endif #include "sysemu/qtest.h" +#ifdef CONFIG_TCG +#include "accel/tcg/perf.h" +#endif #include "disas/disas.h" @@ -2926,6 +2929,14 @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_DFILTER: qemu_set_dfilter_ranges(optarg, &error_fatal); break; +#if defined(CONFIG_TCG) && defined(CONFIG_LINUX) + case QEMU_OPTION_perfmap: + perf_enable_perfmap(); + break; + case QEMU_OPTION_jitdump: + perf_enable_jitdump(); + break; +#endif case QEMU_OPTION_seed: qemu_guest_random_seed_main(optarg, &error_fatal); break; diff --git a/tcg/tcg.c b/tcg/tcg.c index da91779890..9b7df71e7a 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -61,6 +61,7 @@ #include "exec/log.h" #include "tcg/tcg-ldst.h" #include "tcg-internal.h" +#include "accel/tcg/perf.h" /* Forward declarations for functions declared in tcg-target.c.inc and used here. */ @@ -913,6 +914,7 @@ void tcg_prologue_init(TCGContext *s) #endif prologue_size = tcg_current_code_size(s); + perf_report_prologue(s->code_gen_ptr, prologue_size); #ifndef CONFIG_TCG_INTERPRETER flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf), From 701ea5870d3752173d0c78d79d9d1f57757a8036 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 3 Dec 2022 19:31:12 -0600 Subject: [PATCH 068/814] util/bufferiszero: Use __attribute__((target)) for avx2/avx512 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the attribute, which is supported by clang, instead of the #pragma, which is not supported and, for some reason, also not detected by the meson probe, so we fail by -Werror. Include only as that is the outermost "official" header for these intrinsics -- emmintrin.h and smmintrin -- are older SSE2 and SSE4 specific headers, while the immintrin.h includes all of the Intel intrinsics. Reviewed-by: Daniel P. Berrangé Signed-off-by: Richard Henderson --- meson.build | 8 ++------ util/bufferiszero.c | 41 ++++++----------------------------------- 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/meson.build b/meson.build index 6d212f6c8e..58d8cd68a6 100644 --- a/meson.build +++ b/meson.build @@ -2338,11 +2338,9 @@ config_host_data.set('CONFIG_CPUID_H', have_cpuid_h) config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX2') \ .require(cc.links(''' - #pragma GCC push_options - #pragma GCC target("avx2") #include #include - static int bar(void *a) { + static int __attribute__((target("avx2"))) bar(void *a) { __m256i x = *(__m256i *)a; return _mm256_testz_si256(x, x); } @@ -2352,11 +2350,9 @@ config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512F') \ .require(cc.links(''' - #pragma GCC push_options - #pragma GCC target("avx512f") #include #include - static int bar(void *a) { + static int __attribute__((target("avx512f"))) bar(void *a) { __m512i x = *(__m512i *)a; return _mm512_test_epi64_mask(x, x); } diff --git a/util/bufferiszero.c b/util/bufferiszero.c index ec3cd4ca15..1790ded7d4 100644 --- a/util/bufferiszero.c +++ b/util/bufferiszero.c @@ -64,18 +64,11 @@ buffer_zero_int(const void *buf, size_t len) } #if defined(CONFIG_AVX512F_OPT) || defined(CONFIG_AVX2_OPT) || defined(__SSE2__) -/* Do not use push_options pragmas unnecessarily, because clang - * does not support them. - */ -#if defined(CONFIG_AVX512F_OPT) || defined(CONFIG_AVX2_OPT) -#pragma GCC push_options -#pragma GCC target("sse2") -#endif -#include +#include /* Note that each of these vectorized functions require len >= 64. */ -static bool +static bool __attribute__((target("sse2"))) buffer_zero_sse2(const void *buf, size_t len) { __m128i t = _mm_loadu_si128(buf); @@ -104,20 +97,9 @@ buffer_zero_sse2(const void *buf, size_t len) return _mm_movemask_epi8(_mm_cmpeq_epi8(t, zero)) == 0xFFFF; } -#if defined(CONFIG_AVX512F_OPT) || defined(CONFIG_AVX2_OPT) -#pragma GCC pop_options -#endif #ifdef CONFIG_AVX2_OPT -/* Note that due to restrictions/bugs wrt __builtin functions in gcc <= 4.8, - * the includes have to be within the corresponding push_options region, and - * therefore the regions themselves have to be ordered with increasing ISA. - */ -#pragma GCC push_options -#pragma GCC target("sse4") -#include - -static bool +static bool __attribute__((target("sse4"))) buffer_zero_sse4(const void *buf, size_t len) { __m128i t = _mm_loadu_si128(buf); @@ -145,12 +127,7 @@ buffer_zero_sse4(const void *buf, size_t len) return _mm_testz_si128(t, t); } -#pragma GCC pop_options -#pragma GCC push_options -#pragma GCC target("avx2") -#include - -static bool +static bool __attribute__((target("avx2"))) buffer_zero_avx2(const void *buf, size_t len) { /* Begin with an unaligned head of 32 bytes. */ @@ -176,15 +153,10 @@ buffer_zero_avx2(const void *buf, size_t len) return _mm256_testz_si256(t, t); } -#pragma GCC pop_options #endif /* CONFIG_AVX2_OPT */ #ifdef CONFIG_AVX512F_OPT -#pragma GCC push_options -#pragma GCC target("avx512f") -#include - -static bool +static bool __attribute__((target("avx512f"))) buffer_zero_avx512(const void *buf, size_t len) { /* Begin with an unaligned head of 64 bytes. */ @@ -210,8 +182,7 @@ buffer_zero_avx512(const void *buf, size_t len) return !_mm512_test_epi64_mask(t, t); } -#pragma GCC pop_options -#endif +#endif /* CONFIG_AVX512F_OPT */ /* Note that for test_buffer_is_zero_next_accel, the most preferred From 61710a7e23a63546da0071ea32adb96476fa5d07 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 7 Jan 2023 10:12:51 -0800 Subject: [PATCH 069/814] accel/tcg: Split out cpu_exec_{setjmp,loop} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recently the g_assert(cpu == current_cpu) test has been intermittently failing with gcc. Reorg the code around the setjmp to minimize the lifetime of the cpu variable affected by the setjmp. This appears to fix the existing issue with clang as well. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1147 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 111 +++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 356fe348de..8927092537 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -909,64 +909,10 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, /* main execution loop */ -int cpu_exec(CPUState *cpu) +static int __attribute__((noinline)) +cpu_exec_loop(CPUState *cpu, SyncClocks *sc) { int ret; - SyncClocks sc = { 0 }; - - /* replay_interrupt may need current_cpu */ - current_cpu = cpu; - - if (cpu_handle_halt(cpu)) { - return EXCP_HALTED; - } - - rcu_read_lock(); - - cpu_exec_enter(cpu); - - /* Calculate difference between guest clock and host clock. - * This delay includes the delay of the last cycle, so - * what we have to do is sleep until it is 0. As for the - * advance/delay we gain here, we try to fix it next time. - */ - init_delay_params(&sc, cpu); - - /* prepare setjmp context for exception handling */ - if (sigsetjmp(cpu->jmp_env, 0) != 0) { -#if defined(__clang__) - /* - * Some compilers wrongly smash all local variables after - * siglongjmp (the spec requires that only non-volatile locals - * which are changed between the sigsetjmp and siglongjmp are - * permitted to be trashed). There were bug reports for gcc - * 4.5.0 and clang. The bug is fixed in all versions of gcc - * that we support, but is still unfixed in clang: - * https://bugs.llvm.org/show_bug.cgi?id=21183 - * - * Reload an essential local variable here for those compilers. - * Newer versions of gcc would complain about this code (-Wclobbered), - * so we only perform the workaround for clang. - */ - cpu = current_cpu; -#else - /* Non-buggy compilers preserve this; assert the correct value. */ - g_assert(cpu == current_cpu); -#endif - -#ifndef CONFIG_SOFTMMU - clear_helper_retaddr(); - if (have_mmap_lock()) { - mmap_unlock(); - } -#endif - if (qemu_mutex_iothread_locked()) { - qemu_mutex_unlock_iothread(); - } - qemu_plugin_disable_mem_helpers(cpu); - - assert_no_pages_locked(); - } /* if an exception is pending, we execute it here */ while (!cpu_handle_exception(cpu, &ret)) { @@ -1033,9 +979,60 @@ int cpu_exec(CPUState *cpu) /* Try to align the host and virtual clocks if the guest is in advance */ - align_clocks(&sc, cpu); + align_clocks(sc, cpu); } } + return ret; +} + +static int cpu_exec_setjmp(CPUState *cpu, SyncClocks *sc) +{ + /* Prepare setjmp context for exception handling. */ + if (unlikely(sigsetjmp(cpu->jmp_env, 0) != 0)) { + /* Non-buggy compilers preserve this; assert the correct value. */ + g_assert(cpu == current_cpu); + +#ifndef CONFIG_SOFTMMU + clear_helper_retaddr(); + if (have_mmap_lock()) { + mmap_unlock(); + } +#endif + if (qemu_mutex_iothread_locked()) { + qemu_mutex_unlock_iothread(); + } + qemu_plugin_disable_mem_helpers(cpu); + + assert_no_pages_locked(); + } + + return cpu_exec_loop(cpu, sc); +} + +int cpu_exec(CPUState *cpu) +{ + int ret; + SyncClocks sc = { 0 }; + + /* replay_interrupt may need current_cpu */ + current_cpu = cpu; + + if (cpu_handle_halt(cpu)) { + return EXCP_HALTED; + } + + rcu_read_lock(); + cpu_exec_enter(cpu); + + /* + * Calculate difference between guest clock and host clock. + * This delay includes the delay of the last cycle, so + * what we have to do is sleep until it is 0. As for the + * advance/delay we gain here, we try to fix it next time. + */ + init_delay_params(&sc, cpu); + + ret = cpu_exec_setjmp(cpu, &sc); cpu_exec_exit(cpu); rcu_read_unlock(); From 82df11e78d0baef7ffb7e7933c6fb830ffed087c Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 12 Jan 2023 09:34:13 -0500 Subject: [PATCH 070/814] tests/qtest: Poll on waitpid() for a while before sending SIGKILL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prevent getting stuck on waitpid() in case the target process does not terminate on SIGTERM, poll on waitpid() for 30s and if the target process has not changed state until then send a SIGKILL to it. Signed-off-by: Stefan Berger Reviewed-by: Daniel P. Berrangé Message-id: 20230112143413.3979057-1-stefanb@linux.ibm.com [PMM: changed TFR to RETRY_ON_EINTR] --- tests/qtest/libqtest.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 5cb38f90da..6b2216cb20 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -49,6 +49,8 @@ # define DEV_NULL "nul" #endif +#define WAITPID_TIMEOUT 30 + typedef void (*QTestSendFn)(QTestState *s, const char *buf); typedef void (*ExternalSendFn)(void *s, const char *buf); typedef GString* (*QTestRecvFn)(QTestState *); @@ -202,8 +204,24 @@ void qtest_wait_qemu(QTestState *s) { #ifndef _WIN32 pid_t pid; + uint64_t end; + + /* poll for a while until sending SIGKILL */ + end = g_get_monotonic_time() + WAITPID_TIMEOUT * G_TIME_SPAN_SECOND; + + do { + pid = waitpid(s->qemu_pid, &s->wstatus, WNOHANG); + if (pid != 0) { + break; + } + g_usleep(100 * 1000); + } while (g_get_monotonic_time() < end); + + if (pid == 0) { + kill(s->qemu_pid, SIGKILL); + pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0)); + } - pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0)); assert(pid == s->qemu_pid); #else DWORD ret; From 255b00b4def7bac1fd313adca931426f4eb10b05 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 11 Jan 2023 08:45:47 -0500 Subject: [PATCH 071/814] tests/qtest/tpm-emu: Avoid hangs using abort handlers closing channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install abort handlers that close the TPM control and data channels in case an abort occurs. The purpose of this is to have QEMU terminate under abnormal test case failures to resolve intermittent hangs on s390x hosts running TPM tests for QEMU/x86_64. Signed-off-by: Stefan Berger Reviewed-by: Daniel P. Berrangé Message-id: 20230111134547.3959604-1-stefanb@linux.ibm.com --- tests/qtest/tpm-emu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c index 2994d1cf42..73e0000a2c 100644 --- a/tests/qtest/tpm-emu.c +++ b/tests/qtest/tpm-emu.c @@ -36,11 +36,18 @@ void tpm_emu_test_wait_cond(TPMTestState *s) g_mutex_unlock(&s->data_mutex); } +static void tpm_emu_close_ioc(void *ioc) +{ + qio_channel_close(ioc, NULL); +} + static void *tpm_emu_tpm_thread(void *data) { TPMTestState *s = data; QIOChannel *ioc = s->tpm_ioc; + qtest_add_abrt_handler(tpm_emu_close_ioc, ioc); + s->tpm_msg = g_new(struct tpm_hdr, 1); while (true) { int minhlen = sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len); @@ -77,6 +84,7 @@ static void *tpm_emu_tpm_thread(void *data) &error_abort); } + qtest_remove_abrt_handler(ioc); g_free(s->tpm_msg); s->tpm_msg = NULL; object_unref(OBJECT(s->tpm_ioc)); @@ -99,6 +107,7 @@ void *tpm_emu_ctrl_thread(void *data) qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); g_assert(ioc); + qtest_add_abrt_handler(tpm_emu_close_ioc, ioc); { uint32_t cmd = 0; @@ -190,6 +199,7 @@ void *tpm_emu_ctrl_thread(void *data) } } + qtest_remove_abrt_handler(ioc); object_unref(OBJECT(ioc)); object_unref(OBJECT(lioc)); return NULL; From f99ad11cd193f21d8740ca836e2d84315171aefd Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Sat, 26 Nov 2022 19:22:20 -0800 Subject: [PATCH 072/814] hw/cxl/cxl-host: Fix an error message typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hoa Nguyen Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20221127032220.2649-1-hoanguyen@ucdavis.edu> Signed-off-by: Laurent Vivier --- hw/cxl/cxl-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index 1adf61231a..3c1ec8732a 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -47,7 +47,7 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state, if (object->size % (256 * MiB)) { error_setg(errp, - "Size of a CXL fixed memory window must my a multiple of 256MiB"); + "Size of a CXL fixed memory window must be a multiple of 256MiB"); return; } fw->size = object->size; From b93b3cb1bb72f313d8c33791e0a82a25da780cf0 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sat, 5 Nov 2022 14:53:29 +0300 Subject: [PATCH 073/814] hw/ssi/sifive_spi.c: spelling: reigster Fixes: 0694dabe9763847f3010b54ab3ec7d367d2f0ff0 Signed-off-by: Michael Tokarev Reviewed-by: Alistair Francis Reviewed-by: Palmer Dabbelt Acked-by: Palmer Dabbelt Message-Id: <20221105115329.306527-1-mjt@msgid.tls.msk.ru> Signed-off-by: Laurent Vivier --- hw/ssi/sifive_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c index 03540cf5ca..1b4a401ca1 100644 --- a/hw/ssi/sifive_spi.c +++ b/hw/ssi/sifive_spi.c @@ -267,7 +267,7 @@ static void sifive_spi_write(void *opaque, hwaddr addr, case R_RXDATA: case R_IP: qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid write to read-only reigster 0x%" + "%s: invalid write to read-only register 0x%" HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value); break; From b55a8d9d0bb486c0ad7a34985ec43f22fae930c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 12:42:06 -0800 Subject: [PATCH 074/814] tcg: Split out tcg_out_exit_tb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The INDEX_op_exit_tb opcode needs no register allocation. Split out a dedicated helper function for it. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 22 ++++++++++-------- tcg/arm/tcg-target.c.inc | 11 +++++---- tcg/i386/tcg-target.c.inc | 21 +++++++++-------- tcg/loongarch64/tcg-target.c.inc | 22 ++++++++++-------- tcg/mips/tcg-target.c.inc | 33 +++++++++++++-------------- tcg/ppc/tcg-target.c.inc | 11 +++++---- tcg/riscv/tcg-target.c.inc | 22 ++++++++++-------- tcg/s390x/tcg-target.c.inc | 23 ++++++++++--------- tcg/sparc64/tcg-target.c.inc | 39 +++++++++++++++++--------------- tcg/tcg.c | 4 ++++ tcg/tci/tcg-target.c.inc | 10 ++++---- 11 files changed, 121 insertions(+), 97 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index ad1816e32d..501b77c215 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1887,6 +1887,17 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, static const tcg_insn_unit *tb_ret_addr; +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_goto_long(s, tcg_code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); + tcg_out_goto_long(s, tb_ret_addr); + } +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1906,16 +1917,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, #define REG0(I) (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I]) switch (opc) { - case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - if (a0 == 0) { - tcg_out_goto_long(s, tcg_code_gen_epilogue); - } else { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); - tcg_out_goto_long(s, tb_ret_addr); - } - break; - case INDEX_op_goto_tb: tcg_debug_assert(s->tb_jmp_insn_offset != NULL); /* @@ -2305,6 +2306,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 9245ea86d0..799cf13536 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1933,6 +1933,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) static void tcg_out_epilogue(TCGContext *s); +static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, arg); + tcg_out_epilogue(s); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1941,10 +1947,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c; switch (opc) { - case INDEX_op_exit_tb: - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, args[0]); - tcg_out_epilogue(s); - break; case INDEX_op_goto_tb: { /* Indirect jump method */ @@ -2256,6 +2258,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 58bd5873f5..feb257db01 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2347,6 +2347,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #endif } +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_jmp(s, tcg_code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0); + tcg_out_jmp(s, tb_ret_addr); + } +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2371,15 +2382,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const_a2 = const_args[2]; switch (opc) { - case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - if (a0 == 0) { - tcg_out_jmp(s, tcg_code_gen_epilogue); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, a0); - tcg_out_jmp(s, tb_ret_addr); - } - break; case INDEX_op_goto_tb: if (s->tb_jmp_insn_offset) { /* direct jump method */ @@ -2794,6 +2796,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index c9e99e8ec3..29e4bfcb49 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1068,6 +1068,17 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, static const tcg_insn_unit *tb_ret_addr; +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_call_int(s, tcg_code_gen_epilogue, true); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); + tcg_out_call_int(s, tb_ret_addr, true); + } +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1078,16 +1089,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c2 = const_args[2]; switch (opc) { - case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - if (a0 == 0) { - tcg_out_call_int(s, tcg_code_gen_epilogue, true); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); - tcg_out_call_int(s, tb_ret_addr, true); - } - break; - case INDEX_op_goto_tb: tcg_debug_assert(s->tb_jmp_insn_offset != NULL); /* @@ -1500,6 +1501,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 292e490b5c..52881abd35 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1951,6 +1951,21 @@ static void tcg_out_clz(TCGContext *s, MIPSInsn opcv2, MIPSInsn opcv6, } } +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + TCGReg b0 = TCG_REG_ZERO; + + if (a0 & ~0xffff) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff); + b0 = TCG_REG_V0; + } + if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)tb_ret_addr); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); + } + tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1970,23 +1985,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, c2 = const_args[2]; switch (opc) { - case INDEX_op_exit_tb: - { - TCGReg b0 = TCG_REG_ZERO; - - a0 = (intptr_t)a0; - if (a0 & ~0xffff) { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff); - b0 = TCG_REG_V0; - } - if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, - (uintptr_t)tb_ret_addr); - tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); - } - tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff); - } - break; case INDEX_op_goto_tb: /* indirect jump method */ tcg_debug_assert(s->tb_jmp_insn_offset == 0); @@ -2403,6 +2401,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index e0621463f6..a95e4001d3 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2616,6 +2616,12 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out32(s, BCLR | BO_ALWAYS); } +static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, arg); + tcg_out_b(s, 0, tcg_code_gen_epilogue); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2623,10 +2629,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGArg a0, a1, a2; switch (opc) { - case INDEX_op_exit_tb: - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R3, args[0]); - tcg_out_b(s, 0, tcg_code_gen_epilogue); - break; case INDEX_op_goto_tb: if (s->tb_jmp_insn_offset) { /* Direct jump. */ @@ -3185,6 +3187,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f741e0582d..9b42cb4b2e 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1289,6 +1289,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) static const tcg_insn_unit *tb_ret_addr; +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tcg_out_call_int(s, tcg_code_gen_epilogue, true); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); + tcg_out_call_int(s, tb_ret_addr, true); + } +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1299,16 +1310,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c2 = const_args[2]; switch (opc) { - case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - if (a0 == 0) { - tcg_out_call_int(s, tcg_code_gen_epilogue, true); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); - tcg_out_call_int(s, tb_ret_addr, true); - } - break; - case INDEX_op_goto_tb: assert(s->tb_jmp_insn_offset == 0); /* indirect jump method */ @@ -1617,6 +1618,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 2b38fd991d..48a0c3e3c0 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1944,6 +1944,17 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, #endif } +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + /* Reuse the zeroing that exists for goto_ptr. */ + if (a0 == 0) { + tgen_gotoi(s, S390_CC_ALWAYS, tcg_code_gen_epilogue); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0); + tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr); + } +} + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ case glue(glue(INDEX_op_,x),_i64) @@ -1956,17 +1967,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGArg a0, a1, a2; switch (opc) { - case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - a0 = args[0]; - if (a0 == 0) { - tgen_gotoi(s, S390_CC_ALWAYS, tcg_code_gen_epilogue); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, a0); - tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr); - } - break; - case INDEX_op_goto_tb: a0 = args[0]; /* @@ -2619,6 +2619,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index eb913f33c8..d2d8b46815 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1428,6 +1428,26 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, #endif /* CONFIG_SOFTMMU */ } +static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) +{ + if (check_fit_ptr(a0, 13)) { + tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); + tcg_out_movi_imm13(s, TCG_REG_O0, a0); + return; + } else if (USE_REG_TB) { + intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0); + if (check_fit_ptr(tb_diff, 13)) { + tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); + /* Note that TCG_REG_TB has been unwound to O1. */ + tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O1, tb_diff, ARITH_ADD); + return; + } + } + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, a0 & ~0x3ff); + tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); + tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1442,24 +1462,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, c2 = const_args[2]; switch (opc) { - case INDEX_op_exit_tb: - if (check_fit_ptr(a0, 13)) { - tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); - tcg_out_movi_imm13(s, TCG_REG_O0, a0); - break; - } else if (USE_REG_TB) { - intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0); - if (check_fit_ptr(tb_diff, 13)) { - tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); - /* Note that TCG_REG_TB has been unwound to O1. */ - tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O1, tb_diff, ARITH_ADD); - break; - } - } - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I0, a0 & ~0x3ff); - tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); - tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR); - break; case INDEX_op_goto_tb: if (s->tb_jmp_insn_offset) { /* direct jump method */ @@ -1716,6 +1718,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 9b7df71e7a..257479337c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -104,6 +104,7 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, tcg_target_long arg); +static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]); @@ -4718,6 +4719,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) case INDEX_op_call: tcg_reg_alloc_call(s, op); break; + case INDEX_op_exit_tb: + tcg_out_exit_tb(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 d36a7ebdd1..2f3bcce3a7 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -590,6 +590,11 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, # 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); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -597,10 +602,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGOpcode exts; switch (opc) { - case INDEX_op_exit_tb: - tcg_out_op_p(s, opc, (void *)args[0]); - break; - case INDEX_op_goto_tb: tcg_debug_assert(s->tb_jmp_insn_offset == 0); /* indirect jump method. */ @@ -779,6 +780,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } From 3bb8500ef83613cf3d113041b4ba3104136d9aaf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 15:04:26 -0800 Subject: [PATCH 075/814] tcg/i386: Remove unused goto_tb code for indirect jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index feb257db01..c4ff59e9ee 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2383,23 +2383,19 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - if (s->tb_jmp_insn_offset) { - /* direct jump method */ - int gap; - /* jump displacement must be aligned for atomic patching; + qemu_build_assert(TCG_TARGET_HAS_direct_jump); + { + /* + * Jump displacement must be aligned for atomic patching; * see if we need to add extra nops before jump */ - gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr; + int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr; if (gap != 1) { tcg_out_nopn(s, gap - 1); } tcg_out8(s, OPC_JMP_long); /* jmp im */ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); tcg_out32(s, 0); - } else { - /* indirect jump method */ - tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1, - (intptr_t)(s->tb_jmp_target_addr + a0)); } set_jmp_reset_offset(s, a0); break; From cea583d13cb5afdd0d9ac12cb91841f8f33008f7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 15:05:01 -0800 Subject: [PATCH 076/814] tcg/ppc: Remove unused goto_tb code for indirect jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index a95e4001d3..b72e266990 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2630,27 +2630,21 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - if (s->tb_jmp_insn_offset) { - /* Direct jump. */ - if (TCG_TARGET_REG_BITS == 64) { - /* Ensure the next insns are 8 or 16-byte aligned. */ - while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { - tcg_out32(s, NOP); - } - s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); - tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); - tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); - } else { - s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); - tcg_out32(s, B); - s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); - break; + qemu_build_assert(TCG_TARGET_HAS_direct_jump); + /* Direct jump. */ + if (TCG_TARGET_REG_BITS == 64) { + /* Ensure the next insns are 8 or 16-byte aligned. */ + while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { + tcg_out32(s, NOP); } + s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); + tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); + tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); } else { - /* Indirect jump. */ - tcg_debug_assert(s->tb_jmp_insn_offset == NULL); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TB, 0, - (intptr_t)(s->tb_jmp_insn_offset + args[0])); + s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); + tcg_out32(s, B); + s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); + break; } tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); tcg_out32(s, BCCTR | BO_ALWAYS); From 1ce41e044391120e8dd74fc7c9119747fb072632 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 15:05:37 -0800 Subject: [PATCH 077/814] tcg/sparc64: Remove unused goto_tb code for indirect jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 41 +++++++++++------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d2d8b46815..26b00d1638 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -537,17 +537,6 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, return false; } -static void tcg_out_ld_ptr(TCGContext *s, TCGReg ret, const void *arg) -{ - intptr_t diff = tcg_tbrel_diff(s, arg); - if (USE_REG_TB && check_fit_ptr(diff, 13)) { - tcg_out_ld(s, TCG_TYPE_PTR, ret, TCG_REG_TB, diff); - return; - } - tcg_out_movi(s, TCG_TYPE_PTR, ret, (uintptr_t)arg & ~0x3ff); - tcg_out_ld(s, TCG_TYPE_PTR, ret, ret, (uintptr_t)arg & 0x3ff); -} - static void tcg_out_sety(TCGContext *s, TCGReg rs) { tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); @@ -1463,27 +1452,21 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - if (s->tb_jmp_insn_offset) { - /* direct jump method */ - if (USE_REG_TB) { - /* make sure the patch is 8-byte aligned. */ - if ((intptr_t)s->code_ptr & 4) { - tcg_out_nop(s); - } - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); - tcg_out_sethi(s, TCG_REG_T1, 0); - tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); - tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); - } else { - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); - tcg_out32(s, CALL); + qemu_build_assert(TCG_TARGET_HAS_direct_jump); + /* Direct jump. */ + if (USE_REG_TB) { + /* make sure the patch is 8-byte aligned. */ + if ((intptr_t)s->code_ptr & 4) { tcg_out_nop(s); } + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + tcg_out_sethi(s, TCG_REG_T1, 0); + tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); + tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); + tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); } else { - /* indirect jump method */ - tcg_out_ld_ptr(s, TCG_REG_TB, s->tb_jmp_target_addr + a0); - tcg_out_arithi(s, TCG_REG_G0, TCG_REG_TB, 0, JMPL); + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + tcg_out32(s, CALL); tcg_out_nop(s); } set_jmp_reset_offset(s, a0); From 7f83167c612438bb46ef01b5b23f7b2a0827bdc4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 15:09:00 -0800 Subject: [PATCH 078/814] tcg: Replace asserts on tcg_jmp_insn_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test TCG_TARGET_HAS_direct_jump instead of testing an implementation pointer. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 +- tcg/arm/tcg-target.c.inc | 2 +- tcg/loongarch64/tcg-target.c.inc | 2 +- tcg/mips/tcg-target.c.inc | 2 +- tcg/riscv/tcg-target.c.inc | 2 +- tcg/tci/tcg-target.c.inc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 501b77c215..90af096c11 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1918,7 +1918,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - tcg_debug_assert(s->tb_jmp_insn_offset != NULL); + qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* * Ensure that ADRP+ADD are 8-byte aligned so that an atomic * write can be used to patch the target address. diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 799cf13536..033ff90daa 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1953,7 +1953,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, intptr_t ptr, dif, dil; TCGReg base = TCG_REG_PC; - tcg_debug_assert(s->tb_jmp_insn_offset == 0); + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); ptr = (intptr_t)tcg_splitwx_to_rx(s->tb_jmp_target_addr + args[0]); dif = tcg_pcrel_diff(s, (void *)ptr) - 8; dil = sextract32(dif, 0, 12); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 29e4bfcb49..5dd645fd17 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1090,7 +1090,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - tcg_debug_assert(s->tb_jmp_insn_offset != NULL); + qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* * Ensure that patch area is 8-byte aligned so that an * atomic write can be used to patch the target address. diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 52881abd35..02887d7cb1 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1987,7 +1987,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: /* indirect jump method */ - tcg_debug_assert(s->tb_jmp_insn_offset == 0); + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 9b42cb4b2e..b977c8025d 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1311,7 +1311,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - assert(s->tb_jmp_insn_offset == 0); + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method */ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2f3bcce3a7..ad356f1875 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -603,7 +603,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - tcg_debug_assert(s->tb_jmp_insn_offset == 0); + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method. */ tcg_out_op_p(s, opc, s->tb_jmp_target_addr + args[0]); set_jmp_reset_offset(s, args[0]); From b52a2c03b7d36694c21d70bcd46d68aaba5b0840 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 15:18:44 -0800 Subject: [PATCH 079/814] tcg: Introduce set_jmp_insn_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the existing set_jmp_reset_offset. Move any assert for TCG_TARGET_HAS_direct_jump into the new function (which now cannot be build-time). Will be unused if TCG_TARGET_HAS_direct_jump is constant 0, but we can't test for constant in the preprocessor, so just mark it G_GNUC_UNUSED. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 3 +-- tcg/i386/tcg-target.c.inc | 3 +-- tcg/loongarch64/tcg-target.c.inc | 3 +-- tcg/ppc/tcg-target.c.inc | 7 +++---- tcg/s390x/tcg-target.c.inc | 2 +- tcg/sparc64/tcg-target.c.inc | 5 ++--- tcg/tcg.c | 10 ++++++++++ 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 90af096c11..59e6a08e93 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1918,7 +1918,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* * Ensure that ADRP+ADD are 8-byte aligned so that an atomic * write can be used to patch the target address. @@ -1926,7 +1925,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, if ((uintptr_t)s->code_ptr & 7) { tcg_out32(s, NOP); } - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); /* * actual branch destination will be patched by * tb_target_set_jmp_target later diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index c4ff59e9ee..6fb40fe8ba 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2383,7 +2383,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - qemu_build_assert(TCG_TARGET_HAS_direct_jump); { /* * Jump displacement must be aligned for atomic patching; @@ -2394,7 +2393,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_nopn(s, gap - 1); } tcg_out8(s, OPC_JMP_long); /* jmp im */ - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); tcg_out32(s, 0); } set_jmp_reset_offset(s, a0); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 5dd645fd17..bce7340604 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1090,7 +1090,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* * Ensure that patch area is 8-byte aligned so that an * atomic write can be used to patch the target address. @@ -1098,7 +1097,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, if ((uintptr_t)s->code_ptr & 7) { tcg_out_nop(s); } - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); /* * actual branch destination will be patched by * tb_target_set_jmp_target later diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index b72e266990..dbe8ccd353 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2630,20 +2630,19 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* Direct jump. */ if (TCG_TARGET_REG_BITS == 64) { /* Ensure the next insns are 8 or 16-byte aligned. */ while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { tcg_out32(s, NOP); } - s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); + set_jmp_insn_offset(s, args[0]); tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); } else { - s->tb_jmp_insn_offset[args[0]] = tcg_current_code_size(s); + set_jmp_insn_offset(s, args[0]); tcg_out32(s, B); - s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s); + set_jmp_reset_offset(s, args[0]); break; } tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 48a0c3e3c0..c234347d6a 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1977,7 +1977,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out16(s, NOP); } tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); s->code_ptr += 2; set_jmp_reset_offset(s, a0); break; diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 26b00d1638..c3109fe51b 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1452,20 +1452,19 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_tb: - qemu_build_assert(TCG_TARGET_HAS_direct_jump); /* Direct jump. */ if (USE_REG_TB) { /* make sure the patch is 8-byte aligned. */ if ((intptr_t)s->code_ptr & 4) { tcg_out_nop(s); } - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); tcg_out_sethi(s, TCG_REG_T1, 0); tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); } else { - s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + set_jmp_insn_offset(s, a0); tcg_out32(s, CALL); tcg_out_nop(s); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 257479337c..4092dac294 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -313,6 +313,16 @@ static void set_jmp_reset_offset(TCGContext *s, int which) s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); } +static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) +{ + /* + * We will check for overflow at the end of the opcode loop in + * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. + */ + tcg_debug_assert(TCG_TARGET_HAS_direct_jump); + s->tb_jmp_insn_offset[which] = tcg_current_code_size(s); +} + /* Signal overflow, starting over with fewer guest insns. */ static G_NORETURN void tcg_raise_tb_overflow(TCGContext *s) From becc452a367aa681ca0c1fcb688ae0f16b32b11f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 17:42:11 -0800 Subject: [PATCH 080/814] tcg: Introduce get_jmp_target_addr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the existing set_jmp_reset_offset. Include the rw->rx address space conversion done by arm and s390x, and forgotten by mips and riscv. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 2 +- tcg/mips/tcg-target.c.inc | 2 +- tcg/riscv/tcg-target.c.inc | 2 +- tcg/tcg.c | 9 +++++++++ tcg/tci/tcg-target.c.inc | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 033ff90daa..83b6d77e2e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1954,7 +1954,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGReg base = TCG_REG_PC; qemu_build_assert(!TCG_TARGET_HAS_direct_jump); - ptr = (intptr_t)tcg_splitwx_to_rx(s->tb_jmp_target_addr + args[0]); + ptr = get_jmp_target_addr(s, args[0]); dif = tcg_pcrel_diff(s, (void *)ptr) - 8; dil = sextract32(dif, 0, 12); if (dif != dil) { diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 02887d7cb1..c30173ab64 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1989,7 +1989,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, /* indirect jump method */ qemu_build_assert(!TCG_TARGET_HAS_direct_jump); tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO, - (uintptr_t)(s->tb_jmp_target_addr + a0)); + get_jmp_target_addr(s, a0)); tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); tcg_out_nop(s); set_jmp_reset_offset(s, a0); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index b977c8025d..5b2eac6ab8 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1314,7 +1314,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method */ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, - (uintptr_t)(s->tb_jmp_target_addr + a0)); + get_jmp_target_addr(s, a0)); tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); set_jmp_reset_offset(s, a0); break; diff --git a/tcg/tcg.c b/tcg/tcg.c index 4092dac294..2a14fc2a97 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -323,6 +323,15 @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) s->tb_jmp_insn_offset[which] = tcg_current_code_size(s); } +static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) +{ + /* + * Return the read-execute version of the pointer, for the benefit + * of any pc-relative addressing mode. + */ + return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]); +} + /* Signal overflow, starting over with fewer guest insns. */ static G_NORETURN void tcg_raise_tb_overflow(TCGContext *s) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ad356f1875..59daffc0a0 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -605,7 +605,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method. */ - tcg_out_op_p(s, opc, s->tb_jmp_target_addr + args[0]); + tcg_out_op_p(s, opc, (void *)get_jmp_target_addr(s, args[0])); set_jmp_reset_offset(s, args[0]); break; From cf7d6b8e9828784d118eebb6419678d196cd51b5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 17:14:05 -0800 Subject: [PATCH 081/814] tcg: Split out tcg_out_goto_tb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The INDEX_op_goto_tb opcode needs no register allocation. Split out a dedicated helper function for it. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 40 ++++++++++--------- tcg/arm/tcg-target.c.inc | 49 ++++++++++++----------- tcg/i386/tcg-target.c.inc | 33 ++++++++-------- tcg/loongarch64/tcg-target.c.inc | 38 +++++++++--------- tcg/mips/tcg-target.c.inc | 21 +++++----- tcg/ppc/tcg-target.c.inc | 52 ++++++++++++------------ tcg/riscv/tcg-target.c.inc | 20 +++++----- tcg/s390x/tcg-target.c.inc | 31 ++++++++------- tcg/sparc64/tcg-target.c.inc | 68 +++++++++++++++++--------------- tcg/tcg.c | 4 ++ tcg/tci/tcg-target.c.inc | 16 ++++---- 11 files changed, 199 insertions(+), 173 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 59e6a08e93..ad35bee8af 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1898,6 +1898,26 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) } } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* + * Ensure that ADRP+ADD are 8-byte aligned so that an atomic + * write can be used to patch the target address. + */ + if ((uintptr_t)s->code_ptr & 7) { + tcg_out32(s, NOP); + } + set_jmp_insn_offset(s, which); + /* + * actual branch destination will be patched by + * tb_target_set_jmp_target later + */ + tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0); + tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0); + tcg_out_insn(s, 3207, BR, TCG_REG_TMP); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1917,25 +1937,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, #define REG0(I) (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I]) switch (opc) { - case INDEX_op_goto_tb: - /* - * Ensure that ADRP+ADD are 8-byte aligned so that an atomic - * write can be used to patch the target address. - */ - if ((uintptr_t)s->code_ptr & 7) { - tcg_out32(s, NOP); - } - set_jmp_insn_offset(s, a0); - /* - * actual branch destination will be patched by - * tb_target_set_jmp_target later - */ - tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0); - tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0); - tcg_out_insn(s, 3207, BR, TCG_REG_TMP); - set_jmp_reset_offset(s, a0); - break; - case INDEX_op_goto_ptr: tcg_out_insn(s, 3207, BR, a0); break; @@ -2306,6 +2307,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 83b6d77e2e..b8f3b0c634 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1939,6 +1939,31 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) tcg_out_epilogue(s); } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* Indirect jump method */ + intptr_t ptr, dif, dil; + TCGReg base = TCG_REG_PC; + + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); + ptr = get_jmp_target_addr(s, which); + dif = tcg_pcrel_diff(s, (void *)ptr) - 8; + dil = sextract32(dif, 0, 12); + if (dif != dil) { + /* + * The TB is close, but outside the 12 bits addressable by + * the load. We can extend this to 20 bits with a sub of a + * shifted immediate from pc. In the vastly unlikely event + * the code requires more than 1MB, we'll use 2 insns and + * be no worse off. + */ + base = TCG_REG_R0; + tcg_out_movi32(s, COND_AL, base, ptr - dil); + } + tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1947,29 +1972,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c; switch (opc) { - case INDEX_op_goto_tb: - { - /* Indirect jump method */ - intptr_t ptr, dif, dil; - TCGReg base = TCG_REG_PC; - - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); - ptr = get_jmp_target_addr(s, args[0]); - dif = tcg_pcrel_diff(s, (void *)ptr) - 8; - dil = sextract32(dif, 0, 12); - if (dif != dil) { - /* The TB is close, but outside the 12 bits addressable by - the load. We can extend this to 20 bits with a sub of a - shifted immediate from pc. In the vastly unlikely event - the code requires more than 1MB, we'll use 2 insns and - be no worse off. */ - base = TCG_REG_R0; - tcg_out_movi32(s, COND_AL, base, ptr - dil); - } - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil); - set_jmp_reset_offset(s, args[0]); - } - break; case INDEX_op_goto_ptr: tcg_out_b_reg(s, COND_AL, args[0]); break; @@ -2259,6 +2261,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 6fb40fe8ba..33c4139730 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2358,6 +2358,22 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) } } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* + * Jump displacement must be aligned for atomic patching; + * see if we need to add extra nops before jump + */ + int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr; + if (gap != 1) { + tcg_out_nopn(s, gap - 1); + } + tcg_out8(s, OPC_JMP_long); /* jmp im */ + set_jmp_insn_offset(s, which); + tcg_out32(s, 0); + set_jmp_reset_offset(s, which); +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2382,22 +2398,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const_a2 = const_args[2]; switch (opc) { - case INDEX_op_goto_tb: - { - /* - * Jump displacement must be aligned for atomic patching; - * see if we need to add extra nops before jump - */ - int gap = QEMU_ALIGN_PTR_UP(s->code_ptr + 1, 4) - s->code_ptr; - if (gap != 1) { - tcg_out_nopn(s, gap - 1); - } - tcg_out8(s, OPC_JMP_long); /* jmp im */ - set_jmp_insn_offset(s, a0); - tcg_out32(s, 0); - } - set_jmp_reset_offset(s, a0); - break; case INDEX_op_goto_ptr: /* jmp to the given host address (could be epilogue) */ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0); @@ -2792,6 +2792,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index bce7340604..25de7a9ee0 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1079,6 +1079,25 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) } } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* + * Ensure that patch area is 8-byte aligned so that an + * atomic write can be used to patch the target address. + */ + if ((uintptr_t)s->code_ptr & 7) { + tcg_out_nop(s); + } + set_jmp_insn_offset(s, which); + /* + * actual branch destination will be patched by + * tb_target_set_jmp_target later + */ + tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0); + tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1089,24 +1108,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c2 = const_args[2]; switch (opc) { - case INDEX_op_goto_tb: - /* - * Ensure that patch area is 8-byte aligned so that an - * atomic write can be used to patch the target address. - */ - if ((uintptr_t)s->code_ptr & 7) { - tcg_out_nop(s); - } - set_jmp_insn_offset(s, a0); - /* - * actual branch destination will be patched by - * tb_target_set_jmp_target later - */ - tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0); - tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); - set_jmp_reset_offset(s, a0); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -1501,6 +1502,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index c30173ab64..e54df4128b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1966,6 +1966,17 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff); } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* indirect jump method */ + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO, + get_jmp_target_addr(s, which)); + tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); + tcg_out_nop(s); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1985,15 +1996,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, c2 = const_args[2]; switch (opc) { - case INDEX_op_goto_tb: - /* indirect jump method */ - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); - tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO, - get_jmp_target_addr(s, a0)); - tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); - tcg_out_nop(s); - set_jmp_reset_offset(s, a0); - break; case INDEX_op_goto_ptr: /* jmp to the given host address (could be epilogue) */ tcg_out_opc_reg(s, OPC_JR, 0, a0, 0); @@ -2402,6 +2404,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index dbe8ccd353..e56f86c613 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2622,6 +2622,32 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) tcg_out_b(s, 0, tcg_code_gen_epilogue); } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* Direct jump. */ + if (TCG_TARGET_REG_BITS == 64) { + /* Ensure the next insns are 8 or 16-byte aligned. */ + while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { + tcg_out32(s, NOP); + } + set_jmp_insn_offset(s, which); + tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); + tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); + tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); + tcg_out32(s, BCCTR | BO_ALWAYS); + set_jmp_reset_offset(s, which); + if (USE_REG_TB) { + /* For the unlinked case, need to reset TCG_REG_TB. */ + tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB, + -tcg_current_code_size(s)); + } + } else { + set_jmp_insn_offset(s, which); + tcg_out32(s, B); + set_jmp_reset_offset(s, which); + } +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2629,31 +2655,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGArg a0, a1, a2; switch (opc) { - case INDEX_op_goto_tb: - /* Direct jump. */ - if (TCG_TARGET_REG_BITS == 64) { - /* Ensure the next insns are 8 or 16-byte aligned. */ - while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { - tcg_out32(s, NOP); - } - set_jmp_insn_offset(s, args[0]); - tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); - tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); - } else { - set_jmp_insn_offset(s, args[0]); - tcg_out32(s, B); - set_jmp_reset_offset(s, args[0]); - break; - } - tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); - tcg_out32(s, BCCTR | BO_ALWAYS); - set_jmp_reset_offset(s, args[0]); - if (USE_REG_TB) { - /* For the unlinked case, need to reset TCG_REG_TB. */ - tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB, - -tcg_current_code_size(s)); - } - break; case INDEX_op_goto_ptr: tcg_out32(s, MTSPR | RS(args[0]) | CTR); if (USE_REG_TB) { @@ -3181,6 +3182,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 5b2eac6ab8..ee6759f787 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1300,6 +1300,16 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) } } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); + /* indirect jump method */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, + get_jmp_target_addr(s, which)); + tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1310,15 +1320,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, int c2 = const_args[2]; switch (opc) { - case INDEX_op_goto_tb: - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); - /* indirect jump method */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, - get_jmp_target_addr(s, a0)); - tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); - set_jmp_reset_offset(s, a0); - break; - case INDEX_op_goto_ptr: tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0); break; @@ -1619,6 +1620,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: g_assert_not_reached(); } diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index c234347d6a..e008f0efcc 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1955,6 +1955,21 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) } } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* + * Branch displacement must be aligned for atomic patching; + * see if we need to add extra nop before branch + */ + if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) { + tcg_out16(s, NOP); + } + tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); + set_jmp_insn_offset(s, which); + s->code_ptr += 2; + set_jmp_reset_offset(s, which); +} + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ case glue(glue(INDEX_op_,x),_i64) @@ -1967,21 +1982,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGArg a0, a1, a2; switch (opc) { - case INDEX_op_goto_tb: - a0 = args[0]; - /* - * branch displacement must be aligned for atomic patching; - * see if we need to add extra nop before branch - */ - if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) { - tcg_out16(s, NOP); - } - tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); - set_jmp_insn_offset(s, a0); - s->code_ptr += 2; - set_jmp_reset_offset(s, a0); - break; - case INDEX_op_goto_ptr: a0 = args[0]; tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0); @@ -2620,6 +2620,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index c3109fe51b..594767ded8 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1437,6 +1437,41 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) tcg_out_arithi(s, TCG_REG_O0, TCG_REG_O0, a0 & 0x3ff, ARITH_OR); } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + /* Direct jump. */ + if (USE_REG_TB) { + /* make sure the patch is 8-byte aligned. */ + if ((intptr_t)s->code_ptr & 4) { + tcg_out_nop(s); + } + set_jmp_insn_offset(s, which); + tcg_out_sethi(s, TCG_REG_T1, 0); + tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); + tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); + tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); + } else { + set_jmp_insn_offset(s, which); + tcg_out32(s, CALL); + tcg_out_nop(s); + } + set_jmp_reset_offset(s, which); + + /* + * For the unlinked path of goto_tb, we need to reset TCG_REG_TB + * to the beginning of this TB. + */ + if (USE_REG_TB) { + int c = -tcg_current_code_size(s); + if (check_fit_i32(c, 13)) { + tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c); + tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); + } + } +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1451,38 +1486,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, c2 = const_args[2]; switch (opc) { - case INDEX_op_goto_tb: - /* Direct jump. */ - if (USE_REG_TB) { - /* make sure the patch is 8-byte aligned. */ - if ((intptr_t)s->code_ptr & 4) { - tcg_out_nop(s); - } - set_jmp_insn_offset(s, a0); - tcg_out_sethi(s, TCG_REG_T1, 0); - tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); - tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); - } else { - set_jmp_insn_offset(s, a0); - tcg_out32(s, CALL); - tcg_out_nop(s); - } - set_jmp_reset_offset(s, a0); - - /* For the unlinked path of goto_tb, we need to reset - TCG_REG_TB to the beginning of this TB. */ - if (USE_REG_TB) { - c = -tcg_current_code_size(s); - if (check_fit_i32(c, 13)) { - tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, - TCG_REG_T1, ARITH_ADD); - } - } - break; case INDEX_op_goto_ptr: tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); if (USE_REG_TB) { @@ -1701,6 +1704,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 2a14fc2a97..ffa4506e57 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -105,6 +105,7 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, tcg_target_long arg); 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_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]); @@ -4741,6 +4742,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) case INDEX_op_exit_tb: tcg_out_exit_tb(s, op->args[0]); break; + case INDEX_op_goto_tb: + tcg_out_goto_tb(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 59daffc0a0..f2ac356900 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -595,6 +595,14 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) tcg_out_op_p(s, INDEX_op_exit_tb, (void *)arg); } +static void tcg_out_goto_tb(TCGContext *s, int which) +{ + qemu_build_assert(!TCG_TARGET_HAS_direct_jump); + /* indirect jump method. */ + tcg_out_op_p(s, INDEX_op_goto_tb, (void *)get_jmp_target_addr(s, which)); + set_jmp_reset_offset(s, which); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -602,13 +610,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGOpcode exts; switch (opc) { - case INDEX_op_goto_tb: - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); - /* indirect jump method. */ - tcg_out_op_p(s, opc, (void *)get_jmp_target_addr(s, args[0])); - set_jmp_reset_offset(s, args[0]); - break; - case INDEX_op_goto_ptr: tcg_out_op_r(s, opc, args[0]); break; @@ -781,6 +782,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, 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. */ default: tcg_abort(); } From 3a50f424c9e066bee18bfa9cadcd3e21003ca6bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 18:20:57 -0800 Subject: [PATCH 082/814] tcg: Rename TB_JMP_RESET_OFFSET_INVALID to TB_JMP_OFFSET_INVALID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will shortly be used for more than reset. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 8 ++++---- include/exec/exec-all.h | 2 +- tcg/tcg.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 979f8e1107..a4fdce5b72 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -508,10 +508,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->jmp_dest[1] = (uintptr_t)NULL; /* init original jump addresses which have been set during tcg_gen_code() */ - if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) { + if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { tb_reset_jump(tb, 0); } - if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) { + if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { tb_reset_jump(tb, 1); } @@ -693,9 +693,9 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data) if (tb_page_addr1(tb) != -1) { tst->cross_page++; } - if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) { + if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) { tst->direct_jmp_count++; - if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) { + if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) { tst->direct_jmp2_count++; } } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 25e11b0a8d..b4d09c89ab 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -585,8 +585,8 @@ struct TranslationBlock { * setting one of the jump targets (or patching the jump instruction). Only * two of such jumps are supported. */ +#define TB_JMP_OFFSET_INVALID 0xffff /* indicates no jump generated */ uint16_t jmp_reset_offset[2]; /* offset of original jump target */ -#define TB_JMP_RESET_OFFSET_INVALID 0xffff /* indicates no jump generated */ uintptr_t jmp_target_arg[2]; /* target address or offset */ /* diff --git a/tcg/tcg.c b/tcg/tcg.c index ffa4506e57..ff674c5122 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -4666,8 +4666,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) #endif /* Initialize goto_tb jump offsets. */ - tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID; - tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID; + tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; + tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; if (TCG_TARGET_HAS_direct_jump) { tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; From b7e4afbd9f2f9233a37e021f9e8cce472aecdd64 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 18:39:55 -0800 Subject: [PATCH 083/814] tcg: Add gen_tb to TCGContext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can replace four other variables that are references into the TranslationBlock structure. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 +- include/tcg/tcg.h | 11 +++-------- tcg/tcg-op.c | 14 +++++++------- tcg/tcg.c | 14 +++----------- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index a4fdce5b72..9e925c10f3 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -350,7 +350,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->trace_vcpu_dstate = *cpu->trace_dstate; tb_set_page_addr0(tb, phys_pc); tb_set_page_addr1(tb, -1); - tcg_ctx->tb_cflags = cflags; + tcg_ctx->gen_tb = tb; tb_overflow: #ifdef CONFIG_PROFILER diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index b949d75fdd..c2d5430b5a 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -552,20 +552,15 @@ struct TCGContext { int nb_indirects; int nb_ops; - /* goto_tb support */ - tcg_insn_unit *code_buf; - uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */ - uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */ - uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */ - TCGRegSet reserved_regs; - uint32_t tb_cflags; /* cflags of the current TB */ intptr_t current_frame_offset; intptr_t frame_start; intptr_t frame_end; TCGTemp *frame_temp; - tcg_insn_unit *code_ptr; + TranslationBlock *gen_tb; /* tb for which code is being generated */ + tcg_insn_unit *code_buf; /* pointer for start of tb */ + tcg_insn_unit *code_ptr; /* pointer for running end of tb */ #ifdef CONFIG_PROFILER TCGProfile prof; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index cd1cd4e736..9fa9f1b0fd 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -86,7 +86,7 @@ void tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, void tcg_gen_mb(TCGBar mb_type) { - if (tcg_ctx->tb_cflags & CF_PARALLEL) { + if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { tcg_gen_op1(INDEX_op_mb, mb_type); } } @@ -2782,7 +2782,7 @@ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) void tcg_gen_goto_tb(unsigned idx) { /* We tested CF_NO_GOTO_TB in translator_use_goto_tb. */ - tcg_debug_assert(!(tcg_ctx->tb_cflags & CF_NO_GOTO_TB)); + tcg_debug_assert(!(tcg_ctx->gen_tb->cflags & CF_NO_GOTO_TB)); /* We only support two chained exits. */ tcg_debug_assert(idx <= TB_EXIT_IDXMAX); #ifdef CONFIG_DEBUG_TCG @@ -2798,7 +2798,7 @@ void tcg_gen_lookup_and_goto_ptr(void) { TCGv_ptr ptr; - if (tcg_ctx->tb_cflags & CF_NO_GOTO_PTR) { + if (tcg_ctx->gen_tb->cflags & CF_NO_GOTO_PTR) { tcg_gen_exit_tb(NULL, 0); return; } @@ -3165,7 +3165,7 @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, { memop = tcg_canonicalize_memop(memop, 0, 0); - if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { + if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { TCGv_i32 t1 = tcg_temp_new_i32(); TCGv_i32 t2 = tcg_temp_new_i32(); @@ -3203,7 +3203,7 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, { memop = tcg_canonicalize_memop(memop, 1, 0); - if (!(tcg_ctx->tb_cflags & CF_PARALLEL)) { + if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { TCGv_i64 t1 = tcg_temp_new_i64(); TCGv_i64 t2 = tcg_temp_new_i64(); @@ -3364,7 +3364,7 @@ static void * const table_##NAME[(MO_SIZE | MO_BSWAP) + 1] = { \ void tcg_gen_atomic_##NAME##_i32 \ (TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop) \ { \ - if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ + if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \ do_atomic_op_i32(ret, addr, val, idx, memop, table_##NAME); \ } else { \ do_nonatomic_op_i32(ret, addr, val, idx, memop, NEW, \ @@ -3374,7 +3374,7 @@ void tcg_gen_atomic_##NAME##_i32 \ void tcg_gen_atomic_##NAME##_i64 \ (TCGv_i64 ret, TCGv addr, TCGv_i64 val, TCGArg idx, MemOp memop) \ { \ - if (tcg_ctx->tb_cflags & CF_PARALLEL) { \ + if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { \ do_atomic_op_i64(ret, addr, val, idx, memop, table_##NAME); \ } else { \ do_nonatomic_op_i64(ret, addr, val, idx, memop, NEW, \ diff --git a/tcg/tcg.c b/tcg/tcg.c index ff674c5122..4ac7086afe 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -311,7 +311,7 @@ static void set_jmp_reset_offset(TCGContext *s, int which) * We will check for overflow at the end of the opcode loop in * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. */ - s->tb_jmp_reset_offset[which] = tcg_current_code_size(s); + s->gen_tb->jmp_reset_offset[which] = tcg_current_code_size(s); } static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) @@ -321,7 +321,7 @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. */ tcg_debug_assert(TCG_TARGET_HAS_direct_jump); - s->tb_jmp_insn_offset[which] = tcg_current_code_size(s); + s->gen_tb->jmp_target_arg[which] = tcg_current_code_size(s); } static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) @@ -330,7 +330,7 @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) * Return the read-execute version of the pointer, for the benefit * of any pc-relative addressing mode. */ - return (uintptr_t)tcg_splitwx_to_rx(&s->tb_jmp_target_addr[which]); + return (uintptr_t)tcg_splitwx_to_rx(s->gen_tb->jmp_target_arg + which); } /* Signal overflow, starting over with fewer guest insns. */ @@ -4668,14 +4668,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) /* Initialize goto_tb jump offsets. */ tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; - tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset; - if (TCG_TARGET_HAS_direct_jump) { - tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg; - tcg_ctx->tb_jmp_target_addr = NULL; - } else { - tcg_ctx->tb_jmp_insn_offset = NULL; - tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg; - } tcg_reg_alloc_start(s); From 9da6079b2695dcffd8b18890db6cafdf4dc373db Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Nov 2022 18:54:23 -0800 Subject: [PATCH 084/814] tcg: Add TranslationBlock.jmp_insn_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop overloading jmp_target_arg for both offset and address, depending on TCG_TARGET_HAS_direct_jump. Instead, add a new field to hold the jump insn offset and always set the target address in jmp_target_addr[]. This will allow a tcg backend to use either direct or indirect depending on displacement. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 5 ++--- include/exec/exec-all.h | 3 ++- tcg/tcg.c | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8927092537..25c4b04445 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -572,14 +572,13 @@ void cpu_exec_step_atomic(CPUState *cpu) void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { + tb->jmp_target_addr[n] = addr; if (TCG_TARGET_HAS_direct_jump) { - uintptr_t offset = tb->jmp_target_arg[n]; + uintptr_t offset = tb->jmp_insn_offset[n]; uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr; uintptr_t jmp_rx = tc_ptr + offset; uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff; tb_target_set_jmp_target(tc_ptr, jmp_rx, jmp_rw, addr); - } else { - tb->jmp_target_arg[n] = addr; } } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b4d09c89ab..54585a9954 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -587,7 +587,8 @@ struct TranslationBlock { */ #define TB_JMP_OFFSET_INVALID 0xffff /* indicates no jump generated */ uint16_t jmp_reset_offset[2]; /* offset of original jump target */ - uintptr_t jmp_target_arg[2]; /* target address or offset */ + uint16_t jmp_insn_offset[2]; /* offset of direct jump insn */ + uintptr_t jmp_target_addr[2]; /* target address */ /* * Each TB has a NULL-terminated list (jmp_list_head) of incoming jumps. diff --git a/tcg/tcg.c b/tcg/tcg.c index 4ac7086afe..af2af99583 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -321,7 +321,7 @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. */ tcg_debug_assert(TCG_TARGET_HAS_direct_jump); - s->gen_tb->jmp_target_arg[which] = tcg_current_code_size(s); + s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); } static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) @@ -330,7 +330,7 @@ static uintptr_t G_GNUC_UNUSED get_jmp_target_addr(TCGContext *s, int which) * Return the read-execute version of the pointer, for the benefit * of any pc-relative addressing mode. */ - return (uintptr_t)tcg_splitwx_to_rx(s->gen_tb->jmp_target_arg + which); + return (uintptr_t)tcg_splitwx_to_rx(&s->gen_tb->jmp_target_addr[which]); } /* Signal overflow, starting over with fewer guest insns. */ @@ -4668,6 +4668,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start) /* Initialize goto_tb jump offsets. */ tb->jmp_reset_offset[0] = TB_JMP_OFFSET_INVALID; tb->jmp_reset_offset[1] = TB_JMP_OFFSET_INVALID; + tb->jmp_insn_offset[0] = TB_JMP_OFFSET_INVALID; + tb->jmp_insn_offset[1] = TB_JMP_OFFSET_INVALID; tcg_reg_alloc_start(s); From 0fe1c98da9d9abb8e5dc4a67c7e3bcf19aad1e85 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 11:31:20 -0600 Subject: [PATCH 085/814] tcg: Change tb_target_set_jmp_target arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'tc_ptr' and 'addr' with 'tb' and 'n'. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 11 ++++++++--- tcg/aarch64/tcg-target.c.inc | 5 +++-- tcg/aarch64/tcg-target.h | 3 ++- tcg/arm/tcg-target.h | 3 ++- tcg/i386/tcg-target.c.inc | 9 +++++++++ tcg/i386/tcg-target.h | 9 ++------- tcg/loongarch64/tcg-target.c.inc | 5 +++-- tcg/loongarch64/tcg-target.h | 3 ++- tcg/mips/tcg-target.h | 3 ++- tcg/ppc/tcg-target.c.inc | 7 ++++--- tcg/ppc/tcg-target.h | 3 ++- tcg/riscv/tcg-target.h | 3 ++- tcg/s390x/tcg-target.c.inc | 10 ++++++++++ tcg/s390x/tcg-target.h | 10 ++-------- tcg/sparc64/tcg-target.c.inc | 7 ++++--- tcg/sparc64/tcg-target.h | 3 ++- tcg/tci/tcg-target.h | 3 ++- 17 files changed, 61 insertions(+), 36 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 25c4b04445..37c5f91074 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -574,11 +574,16 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { tb->jmp_target_addr[n] = addr; if (TCG_TARGET_HAS_direct_jump) { + /* + * Get the rx view of the structure, from which we find the + * executable code address, and tb_target_set_jmp_target can + * produce a pc-relative displacement to jmp_target_addr[n]. + */ + const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb); uintptr_t offset = tb->jmp_insn_offset[n]; - uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr; - uintptr_t jmp_rx = tc_ptr + offset; + uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset; uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff; - tb_target_set_jmp_target(tc_ptr, jmp_rx, jmp_rw, addr); + tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw); } } diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index ad35bee8af..0b65f2cac1 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1353,9 +1353,10 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, tcg_out_call_int(s, target); } -void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) { + uintptr_t addr = tb->jmp_target_addr[n]; tcg_insn_unit i1, i2; TCGType rt = TCG_TYPE_I64; TCGReg rd = TCG_REG_TMP; diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 413a5410c5..d491c198da 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -152,7 +152,8 @@ typedef enum { #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 0 -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *, int, + uintptr_t, uintptr_t); #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index b7843d2d54..4c1433093c 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -152,7 +152,8 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_MEMORY_BSWAP 0 /* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 33c4139730..c71c3e664d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2374,6 +2374,15 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* patch the branch destination */ + uintptr_t addr = tb->jmp_target_addr[n]; + qatomic_set((int32_t *)jmp_rw, addr - (jmp_rx + 4)); + /* no need to flush icache explicitly */ +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 7edb7f1d9a..7500ceaab9 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -220,13 +220,8 @@ extern bool have_movbe; #define TCG_TARGET_extract_i64_valid(ofs, len) \ (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32) -static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) -{ - /* patch the branch destination */ - qatomic_set((int32_t *)jmp_rw, addr - (jmp_rx + 4)); - /* no need to flush icache explicitly */ -} +void tb_target_set_jmp_target(const TranslationBlock *, int, + uintptr_t, uintptr_t); /* This defines the natural memory order supported by this * architecture before guarantees made by various barrier diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 25de7a9ee0..3174557ce3 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1039,11 +1039,12 @@ static void tcg_out_nop(TCGContext *s) tcg_out32(s, NOP); } -void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) { tcg_insn_unit i1, i2; ptrdiff_t upper, lower; + uintptr_t addr = tb->jmp_target_addr[n]; ptrdiff_t offset = (ptrdiff_t)(addr - jmp_rx) >> 2; if (offset == sextreg(offset, 0, 26)) { diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index e5f7a1f09d..a150c3c7b2 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -171,7 +171,8 @@ typedef enum { #define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #define TCG_TARGET_DEFAULT_MO (0) diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 15721c3e42..d1adf3e326 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -206,7 +206,8 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_MEMORY_BSWAP 1 /* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t) +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t) QEMU_ERROR("code path is reachable"); #define TCG_TARGET_NEED_LDST_LABELS diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index e56f86c613..6f2c8faea6 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1893,11 +1893,12 @@ static inline void ppc64_replace4(uintptr_t rx, uintptr_t rw, flush_idcache_range(rx, rw, 16); } -void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) { tcg_insn_unit i0, i1, i2, i3; - intptr_t tb_diff = addr - tc_ptr; + uintptr_t addr = tb->jmp_target_addr[n]; + intptr_t tb_diff = addr - (uintptr_t)tb->tc.ptr; intptr_t br_diff = addr - (jmp_rx + 4); intptr_t lo, hi; diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index b5cd225cfa..02764c3331 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -180,7 +180,8 @@ extern bool have_vsx; #define TCG_TARGET_HAS_bitsel_vec have_vsx #define TCG_TARGET_HAS_cmpsel_vec 0 -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 1 diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index 232537ccea..bce164fde2 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -166,7 +166,8 @@ typedef enum { #endif /* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #define TCG_TARGET_DEFAULT_MO (0) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e008f0efcc..2d049a4cc7 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1970,6 +1970,16 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* patch the branch destination */ + uintptr_t addr = tb->jmp_target_addr[n]; + intptr_t disp = addr - (jmp_rx - 2); + qatomic_set((int32_t *)jmp_rw, disp / 2); + /* no need to flush icache explicitly */ +} + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ case glue(glue(INDEX_op_,x),_i64) diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 68dcbc6645..57ba165800 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -175,14 +175,8 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) -static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) -{ - /* patch the branch destination */ - intptr_t disp = addr - (jmp_rx - 2); - qatomic_set((int32_t *)jmp_rw, disp / 2); - /* no need to flush icache explicitly */ -} +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw); #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 594767ded8..fdb711bdf6 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1885,10 +1885,11 @@ void tcg_register_jit(const void *buf, size_t buf_size) tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); } -void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, - uintptr_t jmp_rw, uintptr_t addr) +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) { - intptr_t tb_disp = addr - tc_ptr; + uintptr_t addr = tb->jmp_target_addr[n]; + intptr_t tb_disp = addr - (uintptr_t)tb->tc.ptr; intptr_t br_disp = addr - jmp_rx; tcg_insn_unit i1, i2; diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 0044ac8d78..282833bd8d 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -155,7 +155,8 @@ extern bool use_vis3_instructions; #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 1 -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 94ec541b4e..f9ee83d751 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -177,6 +177,7 @@ typedef enum { #define TCG_TARGET_HAS_MEMORY_BSWAP 1 /* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t, uintptr_t); #endif /* TCG_TARGET_H */ From 0012e3516e0f47b3aaf9213aea2c969cf6e8f42a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 16:34:03 -0600 Subject: [PATCH 086/814] tcg: Move tb_target_set_jmp_target declaration to tcg.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 3 +++ tcg/aarch64/tcg-target.h | 4 ---- tcg/arm/tcg-target.h | 5 ----- tcg/i386/tcg-target.h | 3 --- tcg/loongarch64/tcg-target.h | 3 --- tcg/mips/tcg-target.h | 5 ----- tcg/ppc/tcg-target.h | 4 ---- tcg/riscv/tcg-target.h | 4 ---- tcg/s390x/tcg-target.h | 4 ---- tcg/sparc64/tcg-target.h | 4 ---- tcg/tci/tcg-target.h | 4 ---- 11 files changed, 3 insertions(+), 40 deletions(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c2d5430b5a..6f497172f8 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -833,6 +833,9 @@ void tcg_func_start(TCGContext *s); int tcg_gen_code(TCGContext *s, TranslationBlock *tb, target_ulong pc_start); +void tb_target_set_jmp_target(const TranslationBlock *, int, + uintptr_t, uintptr_t); + void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size); TCGTemp *tcg_global_mem_new_internal(TCGType, TCGv_ptr, diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index d491c198da..a585d035d9 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -151,10 +151,6 @@ typedef enum { #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 0 - -void tb_target_set_jmp_target(const TranslationBlock *, int, - uintptr_t, uintptr_t); - #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 4c1433093c..d347a5dc53 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -150,11 +150,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 0 - -/* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 7500ceaab9..d3705da2ed 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -220,9 +220,6 @@ extern bool have_movbe; #define TCG_TARGET_extract_i64_valid(ofs, len) \ (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32) -void tb_target_set_jmp_target(const TranslationBlock *, int, - uintptr_t, uintptr_t); - /* This defines the natural memory order supported by this * architecture before guarantees made by various barrier * instructions. diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index a150c3c7b2..5782c6887c 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -171,9 +171,6 @@ typedef enum { #define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_NEED_LDST_LABELS diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index d1adf3e326..82b40100cf 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -205,11 +205,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 1 -/* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t) - QEMU_ERROR("code path is reachable"); - #define TCG_TARGET_NEED_LDST_LABELS #endif diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 02764c3331..5ffb41fb57 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -180,12 +180,8 @@ extern bool have_vsx; #define TCG_TARGET_HAS_bitsel_vec have_vsx #define TCG_TARGET_HAS_cmpsel_vec 0 -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 1 - #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index bce164fde2..c9af6d592f 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -165,10 +165,6 @@ typedef enum { #define TCG_TARGET_HAS_mulsh_i64 1 #endif -/* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_NEED_LDST_LABELS diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 57ba165800..9f5d1cf1c7 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -174,10 +174,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_MEMORY_BSWAP 1 #define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) - -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t jmp_rx, uintptr_t jmp_rw); - #define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_POOL_LABELS diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 282833bd8d..b78a545581 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -154,10 +154,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_DEFAULT_MO (0) #define TCG_TARGET_HAS_MEMORY_BSWAP 1 - -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #define TCG_TARGET_NEED_POOL_LABELS #endif diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index f9ee83d751..359d62c2f3 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -176,8 +176,4 @@ typedef enum { #define TCG_TARGET_HAS_MEMORY_BSWAP 1 -/* not defined -- call should be eliminated at compile time */ -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t, uintptr_t); - #endif /* TCG_TARGET_H */ From 90c0fee3a28b25d23081b3c435762cadde813ec4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 16:43:18 -0600 Subject: [PATCH 087/814] tcg: Always define tb_target_set_jmp_target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install empty versions for !TCG_TARGET_HAS_direct_jump hosts. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 6 ++++++ tcg/mips/tcg-target.c.inc | 6 ++++++ tcg/riscv/tcg-target.c.inc | 6 ++++++ tcg/tci/tcg-target.c.inc | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index b8f3b0c634..b21dd561fa 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1964,6 +1964,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* Always indirect, nothing to do */ +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e54df4128b..0b5e100cb1 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1977,6 +1977,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* Always indirect, nothing to do */ +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index ee6759f787..e6a3915859 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1310,6 +1310,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* Always indirect, nothing to do */ +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index f2ac356900..54779d86d9 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -603,6 +603,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + /* Always indirect, nothing to do */ +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) From 2fd2e78d1b5281d589eabdf31a21166c80bebd80 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 16:55:40 -0600 Subject: [PATCH 088/814] tcg: Remove TCG_TARGET_HAS_direct_jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have the option to generate direct or indirect goto_tb depending on the dynamic displacement, thus the define is no longer necessary or completely accurate. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 23 +++++++++++------------ tcg/aarch64/tcg-target.h | 1 - tcg/arm/tcg-target.c.inc | 1 - tcg/arm/tcg-target.h | 1 - tcg/i386/tcg-target.h | 1 - tcg/loongarch64/tcg-target.h | 1 - tcg/mips/tcg-target.c.inc | 1 - tcg/mips/tcg-target.h | 1 - tcg/ppc/tcg-target.h | 1 - tcg/riscv/tcg-target.c.inc | 1 - tcg/riscv/tcg-target.h | 1 - tcg/s390x/tcg-target.c.inc | 3 +++ tcg/s390x/tcg-target.h | 1 - tcg/sparc64/tcg-target.h | 1 - tcg/tcg.c | 1 - tcg/tci/tcg-target.c.inc | 1 - tcg/tci/tcg-target.h | 1 - 17 files changed, 14 insertions(+), 27 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 37c5f91074..04cd1f3092 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -572,19 +572,18 @@ void cpu_exec_step_atomic(CPUState *cpu) void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr) { + /* + * Get the rx view of the structure, from which we find the + * executable code address, and tb_target_set_jmp_target can + * produce a pc-relative displacement to jmp_target_addr[n]. + */ + const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb); + uintptr_t offset = tb->jmp_insn_offset[n]; + uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset; + uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff; + tb->jmp_target_addr[n] = addr; - if (TCG_TARGET_HAS_direct_jump) { - /* - * Get the rx view of the structure, from which we find the - * executable code address, and tb_target_set_jmp_target can - * produce a pc-relative displacement to jmp_target_addr[n]. - */ - const TranslationBlock *c_tb = tcg_splitwx_to_rx(tb); - uintptr_t offset = tb->jmp_insn_offset[n]; - uintptr_t jmp_rx = (uintptr_t)tb->tc.ptr + offset; - uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff; - tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw); - } + tb_target_set_jmp_target(c_tb, n, jmp_rx, jmp_rw); } static inline void tb_add_jump(TranslationBlock *tb, int n, diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index a585d035d9..6067446b03 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -123,7 +123,6 @@ typedef enum { #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_direct_jump 1 #define TCG_TARGET_HAS_v64 1 #define TCG_TARGET_HAS_v128 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index b21dd561fa..e1e1c2620d 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1945,7 +1945,6 @@ static void tcg_out_goto_tb(TCGContext *s, int which) intptr_t ptr, dif, dil; TCGReg base = TCG_REG_PC; - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); ptr = get_jmp_target_addr(s, which); dif = tcg_pcrel_diff(s, (void *)ptr) - 8; dil = sextract32(dif, 0, 12); diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index d347a5dc53..91b8954804 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -121,7 +121,6 @@ extern bool use_neon_instructions; #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_direct_jump 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_v64 use_neon_instructions diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index d3705da2ed..5797a55ea0 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -141,7 +141,6 @@ extern bool have_movbe; #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_direct_jump 1 #if TCG_TARGET_REG_BITS == 64 /* Keep target addresses zero-extended in a register. */ diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 5782c6887c..1c3e48d662 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -128,7 +128,6 @@ typedef enum { #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_direct_jump 1 #define TCG_TARGET_HAS_brcond2 0 #define TCG_TARGET_HAS_setcond2 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 0b5e100cb1..6e000d8e69 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1969,7 +1969,6 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { /* indirect jump method */ - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO, get_jmp_target_addr(s, which)); tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0); diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 82b40100cf..7bc8e15293 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -134,7 +134,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_direct_jump 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 5ffb41fb57..f253184915 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -108,7 +108,6 @@ extern bool have_vsx; #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_direct_jump 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index e6a3915859..136fe54d4b 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1302,7 +1302,6 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method */ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, get_jmp_target_addr(s, which)); diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index c9af6d592f..1337bc1f1e 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -121,7 +121,6 @@ typedef enum { #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_direct_jump 0 #define TCG_TARGET_HAS_brcond2 1 #define TCG_TARGET_HAS_setcond2 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 2d049a4cc7..218318feb2 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1973,6 +1973,9 @@ static void tcg_out_goto_tb(TCGContext *s, int which) void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { + if (!HAVE_FACILITY(GEN_INST_EXT)) { + return; + } /* patch the branch destination */ uintptr_t addr = tb->jmp_target_addr[n]; intptr_t disp = addr - (jmp_rx - 2); diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 9f5d1cf1c7..e597e47e60 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -105,7 +105,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extrl_i64_i32 0 #define TCG_TARGET_HAS_extrh_i64_i32 0 -#define TCG_TARGET_HAS_direct_jump 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_div2_i64 1 diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index b78a545581..1d6a5c8b07 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -111,7 +111,6 @@ extern bool use_vis3_instructions; #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_direct_jump 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extrl_i64_i32 1 diff --git a/tcg/tcg.c b/tcg/tcg.c index af2af99583..d502327be2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -320,7 +320,6 @@ static void G_GNUC_UNUSED set_jmp_insn_offset(TCGContext *s, int which) * We will check for overflow at the end of the opcode loop in * tcg_gen_code, where we bound tcg_current_code_size to UINT16_MAX. */ - tcg_debug_assert(TCG_TARGET_HAS_direct_jump); s->gen_tb->jmp_insn_offset[which] = tcg_current_code_size(s); } diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 54779d86d9..bc452007c6 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -597,7 +597,6 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) static void tcg_out_goto_tb(TCGContext *s, int which) { - qemu_build_assert(!TCG_TARGET_HAS_direct_jump); /* indirect jump method. */ tcg_out_op_p(s, INDEX_op_goto_tb, (void *)get_jmp_target_addr(s, which)); set_jmp_reset_offset(s, which); diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 359d62c2f3..1414ab4d5b 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -82,7 +82,6 @@ #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_direct_jump 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 From d59d83a1c38869b1e1a4f957eb939aaa8a342721 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 17:26:23 -0600 Subject: [PATCH 089/814] tcg/aarch64: Reorg goto_tb implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old implementation replaces two insns, swapping between b nop br x30 and adrp x30, addi x30, x30, lo12: br x30 There is a race condition in which a thread could be stopped at the PC of the second insn, and when restarted does not see the complete address computation and branches to nowhere. The new implemetation replaces only one insn, swapping between b br tmp and ldr tmp, br tmp Reported-by: hev Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 66 +++++++++++++++--------------------- tcg/aarch64/tcg-target.h | 2 +- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 0b65f2cac1..330d26b395 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1353,33 +1353,6 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, tcg_out_call_int(s, target); } -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t jmp_rx, uintptr_t jmp_rw) -{ - uintptr_t addr = tb->jmp_target_addr[n]; - tcg_insn_unit i1, i2; - TCGType rt = TCG_TYPE_I64; - TCGReg rd = TCG_REG_TMP; - uint64_t pair; - - ptrdiff_t offset = addr - jmp_rx; - - if (offset == sextract64(offset, 0, 26)) { - i1 = I3206_B | ((offset >> 2) & 0x3ffffff); - i2 = NOP; - } else { - offset = (addr >> 12) - (jmp_rx >> 12); - - /* patch ADRP */ - i1 = I3406_ADRP | (offset & 3) << 29 | (offset & 0x1ffffc) << (5 - 2) | rd; - /* patch ADDI */ - i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd; - } - pair = (uint64_t)i2 << 32 | i1; - qatomic_set((uint64_t *)jmp_rw, pair); - flush_idcache_range(jmp_rx, jmp_rw, 8); -} - static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) { if (!l->has_value) { @@ -1902,23 +1875,40 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { /* - * Ensure that ADRP+ADD are 8-byte aligned so that an atomic - * write can be used to patch the target address. + * Direct branch, or indirect address load, will be patched + * by tb_target_set_jmp_target. Assert indirect load offset + * in range early, regardless of direct branch distance. */ - if ((uintptr_t)s->code_ptr & 7) { - tcg_out32(s, NOP); - } + intptr_t i_off = tcg_pcrel_diff(s, (void *)get_jmp_target_addr(s, which)); + tcg_debug_assert(i_off == sextract64(i_off, 0, 21)); + set_jmp_insn_offset(s, which); - /* - * actual branch destination will be patched by - * tb_target_set_jmp_target later - */ - tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0); - tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0); + tcg_out32(s, I3206_B); tcg_out_insn(s, 3207, BR, TCG_REG_TMP); set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + uintptr_t d_addr = tb->jmp_target_addr[n]; + ptrdiff_t d_offset = d_addr - jmp_rx; + tcg_insn_unit insn; + + /* Either directly branch, or indirect branch load. */ + if (d_offset == sextract64(d_offset, 0, 28)) { + insn = deposit32(I3206_B, 0, 26, d_offset >> 2); + } else { + uintptr_t i_addr = (uintptr_t)&tb->jmp_target_addr[n]; + ptrdiff_t i_offset = i_addr - jmp_rx; + + /* Note that we asserted this in range in tcg_out_goto_tb. */ + insn = deposit32(I3305_LDR | TCG_REG_TMP, 0, 5, i_offset >> 2); + } + qatomic_set((uint32_t *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 6067446b03..8d244292aa 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -15,7 +15,7 @@ #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_TLB_DISPLACEMENT_BITS 24 -#define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) +#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) typedef enum { TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, From 20b6643324a79860dcdfe811ffe4a79942bca21e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 17:45:02 -0600 Subject: [PATCH 090/814] tcg/ppc: Reorg goto_tb implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old ppc64 implementation replaces 2 or 4 insns, which leaves a race condition in which a thread could be stopped at a PC in the middle of the sequence, and when restarted does not see the complete address computation and branches to nowhere. The new implemetation replaces only one insn, swapping between b and mtctr r31 falling through to a general-case indirect branch. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 158 +++++++++++---------------------------- tcg/ppc/tcg-target.h | 3 +- 2 files changed, 44 insertions(+), 117 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 6f2c8faea6..8d6899cf40 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1854,104 +1854,6 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) tcg_out32(s, insn); } -static inline uint64_t make_pair(tcg_insn_unit i1, tcg_insn_unit i2) -{ - if (HOST_BIG_ENDIAN) { - return (uint64_t)i1 << 32 | i2; - } - return (uint64_t)i2 << 32 | i1; -} - -static inline void ppc64_replace2(uintptr_t rx, uintptr_t rw, - tcg_insn_unit i0, tcg_insn_unit i1) -{ -#if TCG_TARGET_REG_BITS == 64 - qatomic_set((uint64_t *)rw, make_pair(i0, i1)); - flush_idcache_range(rx, rw, 8); -#else - qemu_build_not_reached(); -#endif -} - -static inline void ppc64_replace4(uintptr_t rx, uintptr_t rw, - tcg_insn_unit i0, tcg_insn_unit i1, - tcg_insn_unit i2, tcg_insn_unit i3) -{ - uint64_t p[2]; - - p[!HOST_BIG_ENDIAN] = make_pair(i0, i1); - p[HOST_BIG_ENDIAN] = make_pair(i2, i3); - - /* - * There's no convenient way to get the compiler to allocate a pair - * of registers at an even index, so copy into r6/r7 and clobber. - */ - asm("mr %%r6, %1\n\t" - "mr %%r7, %2\n\t" - "stq %%r6, %0" - : "=Q"(*(__int128 *)rw) : "r"(p[0]), "r"(p[1]) : "r6", "r7"); - flush_idcache_range(rx, rw, 16); -} - -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t jmp_rx, uintptr_t jmp_rw) -{ - tcg_insn_unit i0, i1, i2, i3; - uintptr_t addr = tb->jmp_target_addr[n]; - intptr_t tb_diff = addr - (uintptr_t)tb->tc.ptr; - intptr_t br_diff = addr - (jmp_rx + 4); - intptr_t lo, hi; - - if (TCG_TARGET_REG_BITS == 32) { - intptr_t diff = addr - jmp_rx; - tcg_debug_assert(in_range_b(diff)); - qatomic_set((uint32_t *)jmp_rw, B | (diff & 0x3fffffc)); - flush_idcache_range(jmp_rx, jmp_rw, 4); - return; - } - - /* - * For 16-bit displacements, we can use a single add + branch. - * This happens quite often. - */ - if (tb_diff == (int16_t)tb_diff) { - i0 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, tb_diff); - i1 = B | (br_diff & 0x3fffffc); - ppc64_replace2(jmp_rx, jmp_rw, i0, i1); - return; - } - - lo = (int16_t)tb_diff; - hi = (int32_t)(tb_diff - lo); - assert(tb_diff == hi + lo); - i0 = ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, hi >> 16); - i1 = ADDI | TAI(TCG_REG_TB, TCG_REG_TB, lo); - - /* - * Without stq from 2.07, we can only update two insns, - * and those must be the ones that load the target address. - */ - if (!have_isa_2_07) { - ppc64_replace2(jmp_rx, jmp_rw, i0, i1); - return; - } - - /* - * For 26-bit displacements, we can use a direct branch. - * Otherwise we still need the indirect branch, which we - * must restore after a potential direct branch write. - */ - br_diff -= 4; - if (in_range_b(br_diff)) { - i2 = B | (br_diff & 0x3fffffc); - i3 = NOP; - } else { - i2 = MTSPR | RS(TCG_REG_TB) | CTR; - i3 = BCCTR | BO_ALWAYS; - } - ppc64_replace4(jmp_rx, jmp_rw, i0, i1, i2, i3); -} - static void tcg_out_call_int(TCGContext *s, int lk, const tcg_insn_unit *target) { @@ -2625,30 +2527,56 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) static void tcg_out_goto_tb(TCGContext *s, int which) { - /* Direct jump. */ - if (TCG_TARGET_REG_BITS == 64) { - /* Ensure the next insns are 8 or 16-byte aligned. */ - while ((uintptr_t)s->code_ptr & (have_isa_2_07 ? 15 : 7)) { - tcg_out32(s, NOP); - } + uintptr_t ptr = get_jmp_target_addr(s, which); + + if (USE_REG_TB) { + ptrdiff_t offset = tcg_tbrel_diff(s, (void *)ptr); + tcg_out_mem_long(s, LD, LDX, TCG_REG_TB, TCG_REG_TB, offset); + + /* Direct branch will be patched by tb_target_set_jmp_target. */ set_jmp_insn_offset(s, which); - tcg_out32(s, ADDIS | TAI(TCG_REG_TB, TCG_REG_TB, 0)); - tcg_out32(s, ADDI | TAI(TCG_REG_TB, TCG_REG_TB, 0)); tcg_out32(s, MTSPR | RS(TCG_REG_TB) | CTR); + + /* When branch is out of range, fall through to indirect. */ + tcg_out32(s, BCCTR | BO_ALWAYS); + + /* For the unlinked case, need to reset TCG_REG_TB. */ + set_jmp_reset_offset(s, which); + tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB, + -tcg_current_code_size(s)); + } else { + /* Direct branch will be patched by tb_target_set_jmp_target. */ + set_jmp_insn_offset(s, which); + tcg_out32(s, NOP); + + /* When branch is out of range, fall through to indirect. */ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, ptr - (int16_t)ptr); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_REG_TMP1, (int16_t)ptr); + tcg_out32(s, MTSPR | RS(TCG_REG_TMP1) | CTR); tcg_out32(s, BCCTR | BO_ALWAYS); set_jmp_reset_offset(s, which); - if (USE_REG_TB) { - /* For the unlinked case, need to reset TCG_REG_TB. */ - tcg_out_mem_long(s, ADDI, ADD, TCG_REG_TB, TCG_REG_TB, - -tcg_current_code_size(s)); - } - } else { - set_jmp_insn_offset(s, which); - tcg_out32(s, B); - set_jmp_reset_offset(s, which); } } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + uintptr_t addr = tb->jmp_target_addr[n]; + intptr_t diff = addr - jmp_rx; + tcg_insn_unit insn; + + if (in_range_b(diff)) { + insn = B | (diff & 0x3fffffc); + } else if (USE_REG_TB) { + insn = MTSPR | RS(TCG_REG_TB) | CTR; + } else { + insn = NOP; + } + + qatomic_set((uint32_t *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index f253184915..af81c5a57f 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -27,11 +27,10 @@ #ifdef _ARCH_PPC64 # define TCG_TARGET_REG_BITS 64 -# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) #else # define TCG_TARGET_REG_BITS 32 -# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB) #endif +#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) #define TCG_TARGET_NB_REGS 64 #define TCG_TARGET_INSN_UNIT_SIZE 4 From 1e42b4f8079f7486689693187572452bbec2f158 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Nov 2022 08:34:00 +0300 Subject: [PATCH 091/814] tcg/sparc64: Remove USE_REG_TB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is always true for sparc64, so this is dead since 3a5f6805c7ca. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 62 ++++++++++++------------------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index fdb711bdf6..e0b3957149 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -92,7 +92,6 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #endif #define TCG_REG_TB TCG_REG_I1 -#define USE_REG_TB (sizeof(void *) > 4) static const int tcg_target_reg_alloc_order[] = { TCG_REG_L0, @@ -439,7 +438,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, } /* A 13-bit constant relative to the TB. */ - if (!in_prologue && USE_REG_TB) { + if (!in_prologue) { test = tcg_tbrel_diff(s, (void *)arg); if (check_fit_ptr(test, 13)) { tcg_out_arithi(s, ret, TCG_REG_TB, test, ARITH_ADD); @@ -468,7 +467,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret, } /* Use the constant pool, if possible. */ - if (!in_prologue && USE_REG_TB) { + if (!in_prologue) { new_pool_label(s, arg, R_SPARC_13, s->code_ptr, tcg_tbrel_diff(s, NULL)); tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(TCG_REG_TB)); @@ -1015,10 +1014,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) #endif /* We choose TCG_REG_TB such that no move is required. */ - if (USE_REG_TB) { - QEMU_BUILD_BUG_ON(TCG_REG_TB != TCG_REG_I1); - tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB); - } + QEMU_BUILD_BUG_ON(TCG_REG_TB != TCG_REG_I1); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB); tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I1, 0, JMPL); /* delay slot */ @@ -1423,7 +1420,7 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); tcg_out_movi_imm13(s, TCG_REG_O0, a0); return; - } else if (USE_REG_TB) { + } else { intptr_t tb_diff = tcg_tbrel_diff(s, (void *)a0); if (check_fit_ptr(tb_diff, 13)) { tcg_out_arithi(s, TCG_REG_G0, TCG_REG_I7, 8, RETURN); @@ -1439,36 +1436,30 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { + int c; + /* Direct jump. */ - if (USE_REG_TB) { - /* make sure the patch is 8-byte aligned. */ - if ((intptr_t)s->code_ptr & 4) { - tcg_out_nop(s); - } - set_jmp_insn_offset(s, which); - tcg_out_sethi(s, TCG_REG_T1, 0); - tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); - tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); - } else { - set_jmp_insn_offset(s, which); - tcg_out32(s, CALL); + /* make sure the patch is 8-byte aligned. */ + if ((intptr_t)s->code_ptr & 4) { tcg_out_nop(s); } + set_jmp_insn_offset(s, which); + tcg_out_sethi(s, TCG_REG_T1, 0); + tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); + tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); + tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); set_jmp_reset_offset(s, which); /* * For the unlinked path of goto_tb, we need to reset TCG_REG_TB * to the beginning of this TB. */ - if (USE_REG_TB) { - int c = -tcg_current_code_size(s); - if (check_fit_i32(c, 13)) { - tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD); - } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); - } + c = -tcg_current_code_size(s); + if (check_fit_i32(c, 13)) { + tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c); + tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); } } @@ -1488,11 +1479,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_goto_ptr: tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); - if (USE_REG_TB) { - tcg_out_mov_delay(s, TCG_REG_TB, a0); - } else { - tcg_out_nop(s); - } + 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)); @@ -1898,13 +1885,6 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, tcg_debug_assert(tb_disp == (int32_t)tb_disp); tcg_debug_assert(br_disp == (int32_t)br_disp); - if (!USE_REG_TB) { - qatomic_set((uint32_t *)jmp_rw, - deposit32(CALL, 0, 30, br_disp >> 2)); - flush_idcache_range(jmp_rx, jmp_rw, 4); - return; - } - /* This does not exercise the range of the branch, but we do still need to be able to load the new value of TCG_REG_TB. But this does still happen quite often. */ From a228ae3ea7f6fa9e7eda53906471f1cfc400c114 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 5 Dec 2022 18:05:06 -0600 Subject: [PATCH 092/814] tcg/sparc64: Reorg goto_tb implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old sparc64 implementation may replace two insns, which leaves a race condition in which a thread could be stopped at a PC in the middle of the sequence, and when restarted does not see the complete address computation and branches to nowhere. The new implemetation replaces only one insn, swapping between a direct branch and a direct call. The TCG_REG_TB register is loaded from tb->jmp_target_addr[] in the delay slot. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 87 +++++++++++++++--------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index e0b3957149..dd406bc065 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1436,33 +1436,56 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { - int c; + ptrdiff_t off = tcg_tbrel_diff(s, (void *)get_jmp_target_addr(s, which)); - /* Direct jump. */ - /* make sure the patch is 8-byte aligned. */ - if ((intptr_t)s->code_ptr & 4) { - tcg_out_nop(s); - } + /* Direct branch will be patched by tb_target_set_jmp_target. */ set_jmp_insn_offset(s, which); - tcg_out_sethi(s, TCG_REG_T1, 0); - tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, 0, ARITH_OR); - tcg_out_arith(s, TCG_REG_G0, TCG_REG_TB, TCG_REG_T1, JMPL); - tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); + tcg_out32(s, CALL); + /* delay slot */ + tcg_debug_assert(check_fit_ptr(off, 13)); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TB, TCG_REG_TB, off); set_jmp_reset_offset(s, which); /* * For the unlinked path of goto_tb, we need to reset TCG_REG_TB * to the beginning of this TB. */ - c = -tcg_current_code_size(s); - if (check_fit_i32(c, 13)) { - tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, c, ARITH_ADD); + off = -tcg_current_code_size(s); + if (check_fit_i32(off, 13)) { + tcg_out_arithi(s, TCG_REG_TB, TCG_REG_TB, off, ARITH_ADD); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, c); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, off); tcg_out_arith(s, TCG_REG_TB, TCG_REG_TB, TCG_REG_T1, ARITH_ADD); } } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + uintptr_t addr = tb->jmp_target_addr[n]; + intptr_t br_disp = (intptr_t)(addr - jmp_rx) >> 2; + tcg_insn_unit insn; + + br_disp >>= 2; + if (check_fit_ptr(br_disp, 19)) { + /* ba,pt %icc, addr */ + insn = deposit32(INSN_OP(0) | INSN_OP2(1) | INSN_COND(COND_A) + | BPCC_ICC | BPCC_PT, 0, 19, br_disp); + } else if (check_fit_ptr(br_disp, 22)) { + /* ba addr */ + insn = deposit32(INSN_OP(0) | INSN_OP2(2) | INSN_COND(COND_A), + 0, 22, br_disp); + } else { + /* The code_gen_buffer can't be larger than 2GB. */ + tcg_debug_assert(check_fit_ptr(br_disp, 30)); + /* call addr */ + insn = deposit32(CALL, 0, 30, br_disp); + } + + qatomic_set((uint32_t *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1871,39 +1894,3 @@ void tcg_register_jit(const void *buf, size_t buf_size) { tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); } - -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t jmp_rx, uintptr_t jmp_rw) -{ - uintptr_t addr = tb->jmp_target_addr[n]; - intptr_t tb_disp = addr - (uintptr_t)tb->tc.ptr; - intptr_t br_disp = addr - jmp_rx; - tcg_insn_unit i1, i2; - - /* We can reach the entire address space for ILP32. - For LP64, the code_gen_buffer can't be larger than 2GB. */ - tcg_debug_assert(tb_disp == (int32_t)tb_disp); - tcg_debug_assert(br_disp == (int32_t)br_disp); - - /* This does not exercise the range of the branch, but we do - still need to be able to load the new value of TCG_REG_TB. - But this does still happen quite often. */ - if (check_fit_ptr(tb_disp, 13)) { - /* ba,pt %icc, addr */ - i1 = (INSN_OP(0) | INSN_OP2(1) | INSN_COND(COND_A) - | BPCC_ICC | BPCC_PT | INSN_OFF19(br_disp)); - i2 = (ARITH_ADD | INSN_RD(TCG_REG_TB) | INSN_RS1(TCG_REG_TB) - | INSN_IMM13(tb_disp)); - } else if (tb_disp >= 0) { - i1 = SETHI | INSN_RD(TCG_REG_T1) | ((tb_disp & 0xfffffc00) >> 10); - i2 = (ARITH_OR | INSN_RD(TCG_REG_T1) | INSN_RS1(TCG_REG_T1) - | INSN_IMM13(tb_disp & 0x3ff)); - } else { - i1 = SETHI | INSN_RD(TCG_REG_T1) | ((~tb_disp & 0xfffffc00) >> 10); - i2 = (ARITH_XOR | INSN_RD(TCG_REG_T1) | INSN_RS1(TCG_REG_T1) - | INSN_IMM13((tb_disp & 0x3ff) | -0x400)); - } - - qatomic_set((uint64_t *)jmp_rw, deposit64(i2, 32, 32, i1)); - flush_idcache_range(jmp_rx, jmp_rw, 8); -} From 79ffece44472975b582f009b803d454527d43892 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Nov 2022 00:48:47 -0800 Subject: [PATCH 093/814] tcg/arm: Implement direct branch for goto_tb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that tcg can handle direct and indirect goto_tb simultaneously, we can optimistically leave space for a direct branch and fall back to loading the pointer from the TB for an indirect branch. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 52 ++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index e1e1c2620d..6abe94137e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -135,6 +135,8 @@ typedef enum { ARITH_BIC = 0xe << 21, ARITH_MVN = 0xf << 21, + INSN_B = 0x0a000000, + INSN_CLZ = 0x016f0f10, INSN_RBIT = 0x06ff0f30, @@ -546,7 +548,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) static void tcg_out_b_imm(TCGContext *s, ARMCond cond, int32_t offset) { - tcg_out32(s, (cond << 28) | 0x0a000000 | + tcg_out32(s, (cond << 28) | INSN_B | (((offset - 8) >> 2) & 0x00ffffff)); } @@ -1941,32 +1943,52 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) static void tcg_out_goto_tb(TCGContext *s, int which) { - /* Indirect jump method */ - intptr_t ptr, dif, dil; - TCGReg base = TCG_REG_PC; + uintptr_t i_addr; + intptr_t i_disp; - ptr = get_jmp_target_addr(s, which); - dif = tcg_pcrel_diff(s, (void *)ptr) - 8; - dil = sextract32(dif, 0, 12); - if (dif != dil) { + /* Direct branch will be patched by tb_target_set_jmp_target. */ + set_jmp_insn_offset(s, which); + tcg_out32(s, INSN_NOP); + + /* When branch is out of range, fall through to indirect. */ + i_addr = get_jmp_target_addr(s, which); + i_disp = tcg_pcrel_diff(s, (void *)i_addr) - 8; + tcg_debug_assert(i_disp < 0); + if (i_disp >= -0xfff) { + tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, i_disp); + } else { /* * The TB is close, but outside the 12 bits addressable by * the load. We can extend this to 20 bits with a sub of a - * shifted immediate from pc. In the vastly unlikely event - * the code requires more than 1MB, we'll use 2 insns and - * be no worse off. + * shifted immediate from pc. */ - base = TCG_REG_R0; - tcg_out_movi32(s, COND_AL, base, ptr - dil); + int h = -i_disp; + int l = h & 0xfff; + + h = encode_imm_nofail(h - l); + tcg_out_dat_imm(s, COND_AL, ARITH_SUB, TCG_REG_R0, TCG_REG_PC, h); + tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, l); } - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil); set_jmp_reset_offset(s, which); } void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { - /* Always indirect, nothing to do */ + uintptr_t addr = tb->jmp_target_addr[n]; + ptrdiff_t offset = addr - (jmp_rx + 8); + tcg_insn_unit insn; + + /* Either directly branch, or fall through to indirect branch. */ + if (offset == sextract64(offset, 0, 26)) { + /* B */ + insn = deposit32((COND_AL << 28) | INSN_B, 0, 24, offset >> 2); + } else { + insn = INSN_NOP; + } + + qatomic_set((uint32_t *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); } static void tcg_out_op(TCGContext *s, TCGOpcode opc, From 9ae958e4d7504f87c2ecd5915d8c3ede7007f2e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Nov 2022 01:07:25 -0800 Subject: [PATCH 094/814] tcg/riscv: Introduce OPC_NOP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target.c.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 136fe54d4b..82ca86431e 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -267,6 +267,7 @@ typedef enum { #endif OPC_FENCE = 0x0000000f, + OPC_NOP = OPC_ADDI, /* nop = addi r0,r0,0 */ } RISCVInsn; /* @@ -403,7 +404,7 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count) { int i; for (i = 0; i < count; ++i) { - p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0); + p[i] = OPC_NOP; } } From 493c9b19a7fb7f387c4fcf57d3836504d5242bf5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Nov 2022 01:11:56 -0800 Subject: [PATCH 095/814] tcg/riscv: Implement direct branch for goto_tb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that tcg can handle direct and indirect goto_tb simultaneously, we can optimistically leave space for a direct branch and fall back to loading the pointer from the TB for an indirect branch. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target.c.inc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 82ca86431e..fc0edd811f 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1303,7 +1303,11 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { - /* indirect jump method */ + /* Direct branch will be patched by tb_target_set_jmp_target. */ + set_jmp_insn_offset(s, which); + tcg_out32(s, OPC_JAL); + + /* When branch is out of range, fall through to indirect. */ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, get_jmp_target_addr(s, which)); tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); @@ -1313,7 +1317,18 @@ static void tcg_out_goto_tb(TCGContext *s, int which) void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { - /* Always indirect, nothing to do */ + uintptr_t addr = tb->jmp_target_addr[n]; + ptrdiff_t offset = addr - jmp_rx; + tcg_insn_unit insn; + + /* Either directly branch, or fall through to indirect branch. */ + if (offset == sextreg(offset, 0, 20)) { + insn = encode_uj(OPC_JAL, TCG_REG_ZERO, offset); + } else { + insn = OPC_NOP; + } + qatomic_set((uint32_t *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); } static void tcg_out_op(TCGContext *s, TCGOpcode opc, From 5e988b9614e861df7aad03a0fe06a75b5b0d1c82 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Tue, 10 Jan 2023 04:32:01 +0800 Subject: [PATCH 096/814] Upgrade all packages in the FreeBSD VMs to ensure the freshness This (hopefully) fixes the errors that we currently see in the FreeBSD jobs in the gitlab CI: ld-elf.so.1: /usr/local/bin/bash: Undefined symbol "rl_set_timeout" Signed-off-by: Li-Wen Hsu Message-Id: [thuth: Update subject and patch description] Signed-off-by: Thomas Huth --- .gitlab-ci.d/cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index 785b163aa6..502dfd612c 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -53,7 +53,7 @@ x64-freebsd-12-build: CIRRUS_VM_IMAGE_NAME: freebsd-12-4 CIRRUS_VM_CPUS: 8 CIRRUS_VM_RAM: 8G - UPDATE_COMMAND: pkg update + UPDATE_COMMAND: pkg update; pkg upgrade -y INSTALL_COMMAND: pkg install -y TEST_TARGETS: check @@ -66,7 +66,7 @@ x64-freebsd-13-build: CIRRUS_VM_IMAGE_NAME: freebsd-13-1 CIRRUS_VM_CPUS: 8 CIRRUS_VM_RAM: 8G - UPDATE_COMMAND: pkg update + UPDATE_COMMAND: pkg update; pkg upgrade -y INSTALL_COMMAND: pkg install -y TEST_TARGETS: check From 6e6761d8fb640cf3dc58735c050878847eb22fca Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 10 Jan 2023 15:12:50 +0000 Subject: [PATCH 097/814] Makefile: allow 'make uninstall' Meson supports an "uninstall", so we can easily allow it to work by not suppressing the forwarding of it from Make to meson. We originally suppressed this because Meson's 'uninstall' has a hole in it: it will remove everything that is installed by a mechanism meson knows about, but not things installed by "custom install scripts", and there is no "custom uninstall script" mechanism. For QEMU, though, the only thing that was being installed by a custom install script was the LC_MESSAGES files handled by Meson's i18n module, and that code was fixed in Meson commit 487d45c1e5bfff0fbdb4, which is present in Meson 0.60.0 and later. Since we already require a Meson version newer than that, we're now safe to enable 'uninstall', as it will now correctly uninstall everything that was installed. Signed-off-by: Peter Maydell Resolves: https://gitlab.com/qemu-project/qemu/-/issues/109 Message-Id: <20230110151250.24434-1-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a48103cc8a..ce2f83a684 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,7 @@ NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ ninja-cmd-goals = $(or $(MAKECMDGOALS), all) ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)) -makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall +makefile-targets := build.ninja ctags TAGS cscope dist clean # "ninja -t targets" also lists all prerequisites. If build system # files are marked as PHONY, however, Make will always try to execute # "ninja build.ninja". From 883f2c591fee552067e160208b4fe0228dbabbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 22:29:47 +0100 Subject: [PATCH 098/814] bulk: Rename TARGET_FMT_plx -> HWADDR_FMT_plx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'hwaddr' type is defined in "exec/hwaddr.h" as: hwaddr is the type of a physical address (its size can be different from 'target_ulong'). All definitions use the 'HWADDR_' prefix, except TARGET_FMT_plx: $ fgrep define include/exec/hwaddr.h #define HWADDR_H #define HWADDR_BITS 64 #define HWADDR_MAX UINT64_MAX #define TARGET_FMT_plx "%016" PRIx64 ^^^^^^ #define HWADDR_PRId PRId64 #define HWADDR_PRIi PRIi64 #define HWADDR_PRIo PRIo64 #define HWADDR_PRIu PRIu64 #define HWADDR_PRIx PRIx64 #define HWADDR_PRIX PRIX64 Since hwaddr's size can be *different* from target_ulong, it is very confusing to read one of its format using the 'TARGET_FMT_' prefix, normally used for the target_long / target_ulong types: $ fgrep TARGET_FMT_ include/exec/cpu-defs.h #define TARGET_FMT_lx "%08x" #define TARGET_FMT_ld "%d" #define TARGET_FMT_lu "%u" #define TARGET_FMT_lx "%016" PRIx64 #define TARGET_FMT_ld "%" PRId64 #define TARGET_FMT_lu "%" PRIu64 Apparently this format was missed during commit a8170e5e97 ("Rename target_phys_addr_t to hwaddr"), so complete it by doing a bulk-rename with: $ sed -i -e s/TARGET_FMT_plx/HWADDR_FMT_plx/g $(git grep -l TARGET_FMT_plx) Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230110212947.34557-1-philmd@linaro.org> [thuth: Fix some warnings from checkpatch.pl along the way] Signed-off-by: Thomas Huth --- accel/tcg/cputlb.c | 2 +- hw/arm/strongarm.c | 24 ++++++++++---------- hw/block/pflash_cfi01.c | 2 +- hw/char/digic-uart.c | 4 ++-- hw/char/etraxfs_ser.c | 4 ++-- hw/core/loader.c | 8 +++---- hw/core/sysbus.c | 4 ++-- hw/display/cirrus_vga.c | 4 ++-- hw/display/g364fb.c | 4 ++-- hw/display/vga.c | 8 +++---- hw/dma/etraxfs_dma.c | 34 ++++++++++++++--------------- hw/dma/pl330.c | 14 ++++++------ hw/dma/xilinx_axidma.c | 4 ++-- hw/dma/xlnx_csu_dma.c | 4 ++-- hw/i2c/mpc_i2c.c | 4 ++-- hw/i386/multiboot.c | 8 +++---- hw/i386/xen/xen-hvm.c | 8 +++---- hw/i386/xen/xen-mapcache.c | 16 +++++++------- hw/i386/xen/xen_platform.c | 4 ++-- hw/intc/arm_gicv3_dist.c | 8 +++---- hw/intc/arm_gicv3_its.c | 14 ++++++------ hw/intc/arm_gicv3_redist.c | 8 +++---- hw/intc/exynos4210_combiner.c | 10 ++++----- hw/misc/auxbus.c | 2 +- hw/misc/ivshmem.c | 6 ++--- hw/misc/macio/mac_dbdma.c | 4 ++-- hw/misc/mst_fpga.c | 4 ++-- hw/net/allwinner-sun8i-emac.c | 4 ++-- hw/net/allwinner_emac.c | 4 ++-- hw/net/fsl_etsec/etsec.c | 4 ++-- hw/net/fsl_etsec/rings.c | 4 ++-- hw/net/pcnet.c | 4 ++-- hw/net/rocker/rocker.c | 26 +++++++++++----------- hw/net/rocker/rocker_desc.c | 2 +- hw/net/xilinx_axienet.c | 4 ++-- hw/net/xilinx_ethlite.c | 6 ++--- hw/pci-bridge/pci_expander_bridge.c | 2 +- hw/pci-host/bonito.c | 14 ++++++------ hw/pci-host/ppce500.c | 4 ++-- hw/pci/pci_host.c | 4 ++-- hw/ppc/ppc4xx_sdram.c | 2 +- hw/rtc/exynos4210_rtc.c | 4 ++-- hw/sh4/sh7750.c | 4 ++-- hw/ssi/xilinx_spi.c | 4 ++-- hw/ssi/xilinx_spips.c | 8 +++---- hw/timer/digic-timer.c | 4 ++-- hw/timer/etraxfs_timer.c | 3 +-- hw/timer/exynos4210_mct.c | 2 +- hw/timer/exynos4210_pwm.c | 4 ++-- hw/virtio/virtio-mmio.c | 4 ++-- hw/xen/xen_pt.c | 4 ++-- include/exec/hwaddr.h | 2 +- monitor/misc.c | 2 +- softmmu/memory.c | 18 +++++++-------- softmmu/memory_mapping.c | 4 ++-- softmmu/physmem.c | 10 ++++----- target/i386/monitor.c | 6 ++--- target/loongarch/tlb_helper.c | 2 +- target/microblaze/op_helper.c | 2 +- target/mips/tcg/sysemu/tlb_helper.c | 2 +- target/ppc/mmu-hash32.c | 14 ++++++------ target/ppc/mmu-hash64.c | 12 +++++----- target/ppc/mmu_common.c | 26 +++++++++++----------- target/ppc/mmu_helper.c | 4 ++-- target/riscv/cpu_helper.c | 10 ++++----- target/riscv/monitor.c | 2 +- target/sparc/ldst_helper.c | 6 ++--- target/sparc/mmu_helper.c | 10 ++++----- target/tricore/helper.c | 2 +- 69 files changed, 237 insertions(+), 238 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 4948729917..4e040a1cb9 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1142,7 +1142,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, &xlat, &sz, full->attrs, &prot); assert(sz >= TARGET_PAGE_SIZE); - tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx + tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" HWADDR_FMT_plx " prot=%x idx=%d\n", vaddr, full->phys_addr, prot, mmu_idx); diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 39b8f01ac4..cc73145053 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -151,7 +151,7 @@ static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset, case ICPR: return s->pending; default: - printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", __func__, offset); return 0; } @@ -173,7 +173,7 @@ static void strongarm_pic_mem_write(void *opaque, hwaddr offset, s->int_idle = (value & 1) ? 0 : ~0; break; default: - printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", __func__, offset); break; } @@ -333,7 +333,7 @@ static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr, ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); return 0; } } @@ -375,7 +375,7 @@ static void strongarm_rtc_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); } } @@ -581,7 +581,7 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset, return s->status; default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); } return 0; @@ -626,7 +626,7 @@ static void strongarm_gpio_write(void *opaque, hwaddr offset, break; default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); } } @@ -782,7 +782,7 @@ static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset, return s->ppfr | ~0x7f001; default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); } return 0; @@ -817,7 +817,7 @@ static void strongarm_ppc_write(void *opaque, hwaddr offset, break; default: - printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); } } @@ -1164,7 +1164,7 @@ static uint64_t strongarm_uart_read(void *opaque, hwaddr addr, return s->utsr1; default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); return 0; } } @@ -1221,7 +1221,7 @@ static void strongarm_uart_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); } } @@ -1443,7 +1443,7 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr, strongarm_ssp_fifo_update(s); return retval; default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); break; } return 0; @@ -1509,7 +1509,7 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr, break; default: - printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); break; } } diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 0cbc2fb4cb..36d68c70f6 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -645,7 +645,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, error_flash: qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " - "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" + "(offset " HWADDR_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); mode_read_array: diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index 00e5df5517..51d4e7db52 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -63,7 +63,7 @@ static uint64_t digic_uart_read(void *opaque, hwaddr addr, default: qemu_log_mask(LOG_UNIMP, "digic-uart: read access to unknown register 0x" - TARGET_FMT_plx "\n", addr << 2); + HWADDR_FMT_plx "\n", addr << 2); } return ret; @@ -101,7 +101,7 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, default: qemu_log_mask(LOG_UNIMP, "digic-uart: write access to unknown register 0x" - TARGET_FMT_plx "\n", addr << 2); + HWADDR_FMT_plx "\n", addr << 2); } } diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c index e8c3017724..8d6422dae4 100644 --- a/hw/char/etraxfs_ser.c +++ b/hw/char/etraxfs_ser.c @@ -113,7 +113,7 @@ ser_read(void *opaque, hwaddr addr, unsigned int size) break; default: r = s->regs[addr]; - D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r)); + D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, r)); break; } return r; @@ -127,7 +127,7 @@ ser_write(void *opaque, hwaddr addr, uint32_t value = val64; unsigned char ch = val64; - D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value)); + D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, value)); addr >>= 2; switch (addr) { diff --git a/hw/core/loader.c b/hw/core/loader.c index 55dbe2e199..173f8f67f6 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1059,7 +1059,7 @@ ssize_t rom_add_file(const char *file, const char *fw_dir, rom->mr = mr; snprintf(devpath, sizeof(devpath), "/rom@%s", file); } else { - snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); + snprintf(devpath, sizeof(devpath), "/rom@" HWADDR_FMT_plx, addr); } } @@ -1243,10 +1243,10 @@ static void rom_print_one_overlap_error(Rom *last_rom, Rom *rom) "\nThe following two regions overlap (in the %s address space):\n", rom_as_name(rom)); error_printf( - " %s (addresses 0x" TARGET_FMT_plx " - 0x" TARGET_FMT_plx ")\n", + " %s (addresses 0x" HWADDR_FMT_plx " - 0x" HWADDR_FMT_plx ")\n", last_rom->name, last_rom->addr, last_rom->addr + last_rom->romsize); error_printf( - " %s (addresses 0x" TARGET_FMT_plx " - 0x" TARGET_FMT_plx ")\n", + " %s (addresses 0x" HWADDR_FMT_plx " - 0x" HWADDR_FMT_plx ")\n", rom->name, rom->addr, rom->addr + rom->romsize); } @@ -1600,7 +1600,7 @@ HumanReadableText *qmp_x_query_roms(Error **errp) rom->romsize, rom->name); } else if (!rom->fw_file) { - g_string_append_printf(buf, "addr=" TARGET_FMT_plx + g_string_append_printf(buf, "addr=" HWADDR_FMT_plx " size=0x%06zx mem=%s name=\"%s\"\n", rom->addr, rom->romsize, rom->isrom ? "rom" : "ram", diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 05c1da3d31..35f902b582 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -269,7 +269,7 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) for (i = 0; i < s->num_mmio; i++) { size = memory_region_size(s->mmio[i].memory); - monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", + monitor_printf(mon, "%*smmio " HWADDR_FMT_plx "/" HWADDR_FMT_plx "\n", indent, "", s->mmio[i].addr, size); } } @@ -289,7 +289,7 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev) } } if (s->num_mmio) { - return g_strdup_printf("%s@" TARGET_FMT_plx, qdev_fw_name(dev), + return g_strdup_printf("%s@" HWADDR_FMT_plx, qdev_fw_name(dev), s->mmio[0].addr); } if (s->num_pio) { diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 55c32e3e40..b80f98b6c4 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2041,7 +2041,7 @@ static uint64_t cirrus_vga_mem_read(void *opaque, } else { val = 0xff; qemu_log_mask(LOG_GUEST_ERROR, - "cirrus: mem_readb 0x" TARGET_FMT_plx "\n", addr); + "cirrus: mem_readb 0x" HWADDR_FMT_plx "\n", addr); } return val; } @@ -2105,7 +2105,7 @@ static void cirrus_vga_mem_write(void *opaque, } } else { qemu_log_mask(LOG_GUEST_ERROR, - "cirrus: mem_writeb 0x" TARGET_FMT_plx " " + "cirrus: mem_writeb 0x" HWADDR_FMT_plx " " "value 0x%02" PRIx64 "\n", addr, mem_value); } } diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index caca86d773..2903cab82d 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -320,7 +320,7 @@ static uint64_t g364fb_ctrl_read(void *opaque, break; default: { - error_report("g364: invalid read at [" TARGET_FMT_plx "]", + error_report("g364: invalid read at [" HWADDR_FMT_plx "]", addr); val = 0; break; @@ -424,7 +424,7 @@ static void g364fb_ctrl_write(void *opaque, break; default: error_report("g364: invalid write of 0x%" PRIx64 - " at [" TARGET_FMT_plx "]", val, addr); + " at [" HWADDR_FMT_plx "]", val, addr); break; } } diff --git a/hw/display/vga.c b/hw/display/vga.c index 0cb26a791b..7a5fdff649 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -875,7 +875,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) uint32_t write_mask, bit_mask, set_mask; #ifdef DEBUG_VGA_MEM - printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val); + printf("vga: [0x" HWADDR_FMT_plx "] = 0x%02x\n", addr, val); #endif /* convert to VGA memory offset */ memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3; @@ -909,7 +909,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) assert(addr < s->vram_size); s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM - printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); + printf("vga: chain4: [0x" HWADDR_FMT_plx "]\n", addr); #endif s->plane_updated |= mask; /* only used to detect font change */ memory_region_set_dirty(&s->vram, addr, 1); @@ -925,7 +925,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) } s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM - printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); + printf("vga: odd/even: [0x" HWADDR_FMT_plx "]\n", addr); #endif s->plane_updated |= mask; /* only used to detect font change */ memory_region_set_dirty(&s->vram, addr, 1); @@ -1003,7 +1003,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); #ifdef DEBUG_VGA_MEM - printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n", + printf("vga: latch: [0x" HWADDR_FMT_plx "] mask=0x%08x val=0x%08x\n", addr * 4, write_mask, val); #endif memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t)); diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c index c4334e87bf..0fef00c6c9 100644 --- a/hw/dma/etraxfs_dma.c +++ b/hw/dma/etraxfs_dma.c @@ -269,34 +269,34 @@ static void channel_load_c(struct fs_dma_ctrl *ctrl, int c) static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) { - hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); + hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); - /* Load and decode. FIXME: handle endianness. */ - D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); + /* Load and decode. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr)); cpu_physical_memory_read(addr, &ctrl->channels[c].current_d, sizeof(ctrl->channels[c].current_d)); - D(dump_d(c, &ctrl->channels[c].current_d)); - ctrl->channels[c].regs[RW_DATA] = addr; + D(dump_d(c, &ctrl->channels[c].current_d)); + ctrl->channels[c].regs[RW_DATA] = addr; } static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) { - hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN); + hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN); - /* Encode and store. FIXME: handle endianness. */ - D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); - D(dump_d(c, &ctrl->channels[c].current_d)); + /* Encode and store. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr)); + D(dump_d(c, &ctrl->channels[c].current_d)); cpu_physical_memory_write(addr, &ctrl->channels[c].current_c, sizeof(ctrl->channels[c].current_c)); } static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) { - hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); + hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); - /* Encode and store. FIXME: handle endianness. */ - D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); + /* Encode and store. FIXME: handle endianness. */ + D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr)); cpu_physical_memory_write(addr, &ctrl->channels[c].current_d, sizeof(ctrl->channels[c].current_d)); } @@ -574,8 +574,8 @@ static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c) static uint32_t dma_rinvalid (void *opaque, hwaddr addr) { - hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr); - return 0; + hw_error("Unsupported short raccess. reg=" HWADDR_FMT_plx "\n", addr); + return 0; } static uint64_t @@ -603,7 +603,7 @@ dma_read(void *opaque, hwaddr addr, unsigned int size) default: r = ctrl->channels[c].regs[addr]; - D(printf ("%s c=%d addr=" TARGET_FMT_plx "\n", + D(printf("%s c=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr)); break; } @@ -613,7 +613,7 @@ dma_read(void *opaque, hwaddr addr, unsigned int size) static void dma_winvalid (void *opaque, hwaddr addr, uint32_t value) { - hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr); + hw_error("Unsupported short waccess. reg=" HWADDR_FMT_plx "\n", addr); } static void @@ -686,7 +686,7 @@ dma_write(void *opaque, hwaddr addr, break; default: - D(printf ("%s c=%d " TARGET_FMT_plx "\n", + D(printf("%s c=%d " HWADDR_FMT_plx "\n", __func__, c, addr)); break; } diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index e5d521c329..e7e67dd8b6 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -1373,7 +1373,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset, pl330_exec(s); } else { qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u " - "for offset " TARGET_FMT_plx "\n", (unsigned)value, + "for offset " HWADDR_FMT_plx "\n", (unsigned)value, offset); } break; @@ -1384,7 +1384,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset, s->dbg[1] = value; break; default: - qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " HWADDR_FMT_plx "\n", offset); break; } @@ -1409,7 +1409,7 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, chan_id = offset >> 5; if (chan_id >= s->num_chnls) { qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return 0; } switch (offset & 0x1f) { @@ -1425,7 +1425,7 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, return s->chan[chan_id].lc[1]; default: qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return 0; } } @@ -1434,7 +1434,7 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, chan_id = offset >> 3; if (chan_id >= s->num_chnls) { qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return 0; } switch ((offset >> 2) & 1) { @@ -1456,7 +1456,7 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, chan_id = offset >> 2; if (chan_id >= s->num_chnls) { qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return 0; } return s->chan[chan_id].fault_type; @@ -1495,7 +1495,7 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, return s->debug_status; default: qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); } return 0; } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index cbb8f0f169..6030c76435 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -456,7 +456,7 @@ static uint64_t axidma_read(void *opaque, hwaddr addr, break; default: r = s->regs[addr]; - D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n", + D(qemu_log("%s ch=%d addr=" HWADDR_FMT_plx " v=%x\n", __func__, sid, addr * 4, r)); break; } @@ -509,7 +509,7 @@ static void axidma_write(void *opaque, hwaddr addr, } break; default: - D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n", + D(qemu_log("%s: ch=%d addr=" HWADDR_FMT_plx " v=%x\n", __func__, sid, addr * 4, (unsigned)value)); s->regs[addr] = value; break; diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 1ce52ea5a2..88002698a1 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -211,7 +211,7 @@ static uint32_t xlnx_csu_dma_read(XlnxCSUDMA *s, uint8_t *buf, uint32_t len) if (result == MEMTX_OK) { xlnx_csu_dma_data_process(s, buf, len); } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " TARGET_FMT_plx + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " HWADDR_FMT_plx " for mem read", __func__, addr); s->regs[R_INT_STATUS] |= R_INT_STATUS_AXI_BRESP_ERR_MASK; xlnx_csu_dma_update_irq(s); @@ -241,7 +241,7 @@ static uint32_t xlnx_csu_dma_write(XlnxCSUDMA *s, uint8_t *buf, uint32_t len) } if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " TARGET_FMT_plx + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address " HWADDR_FMT_plx " for mem write", __func__, addr); s->regs[R_INT_STATUS] |= R_INT_STATUS_AXI_BRESP_ERR_MASK; xlnx_csu_dma_update_irq(s); diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c index 845392505f..219c548402 100644 --- a/hw/i2c/mpc_i2c.c +++ b/hw/i2c/mpc_i2c.c @@ -224,7 +224,7 @@ static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size) break; } - DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, + DPRINTF("%s: addr " HWADDR_FMT_plx " %02" PRIx32 "\n", __func__, addr, value); return (uint64_t)value; } @@ -234,7 +234,7 @@ static void mpc_i2c_write(void *opaque, hwaddr addr, { MPCI2CState *s = opaque; - DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__, + DPRINTF("%s: addr " HWADDR_FMT_plx " val %08" PRIx64 "\n", __func__, addr, value); switch (addr) { case MPC_I2C_ADR: diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 963e29362e..3332712ab3 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -137,7 +137,7 @@ static void mb_add_mod(MultibootState *s, stl_p(p + MB_MOD_END, end); stl_p(p + MB_MOD_CMDLINE, cmdline_phys); - mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx, + mb_debug("mod%02d: "HWADDR_FMT_plx" - "HWADDR_FMT_plx, s->mb_mods_count, start, end); s->mb_mods_count++; @@ -353,7 +353,7 @@ int load_multiboot(X86MachineState *x86ms, mb_add_mod(&mbs, mbs.mb_buf_phys + offs, mbs.mb_buf_phys + offs + mb_mod_length, c); - mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx, + mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "HWADDR_FMT_plx, (char *)mbs.mb_buf + offs, (char *)mbs.mb_buf + offs + mb_mod_length, c); g_free(one_file); @@ -382,8 +382,8 @@ int load_multiboot(X86MachineState *x86ms, stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP); mb_debug("multiboot: entry_addr = %#x", mh_entry_addr); - mb_debug(" mb_buf_phys = "TARGET_FMT_plx, mbs.mb_buf_phys); - mb_debug(" mod_start = "TARGET_FMT_plx, + mb_debug(" mb_buf_phys = "HWADDR_FMT_plx, mbs.mb_buf_phys); + mb_debug(" mod_start = "HWADDR_FMT_plx, mbs.mb_buf_phys + mbs.offset_mods); mb_debug(" mb_mods_count = %d", mbs.mb_mods_count); diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index e4293d6d66..b9a6f7f538 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -516,13 +516,13 @@ static void xen_set_memory(struct MemoryListener *listener, if (xen_set_mem_type(xen_domid, mem_type, start_addr >> TARGET_PAGE_BITS, size >> TARGET_PAGE_BITS)) { - DPRINTF("xen_set_mem_type error, addr: "TARGET_FMT_plx"\n", + DPRINTF("xen_set_mem_type error, addr: "HWADDR_FMT_plx"\n", start_addr); } } } else { if (xen_remove_from_physmap(state, start_addr, size) < 0) { - DPRINTF("physmapping does not exist at "TARGET_FMT_plx"\n", start_addr); + DPRINTF("physmapping does not exist at "HWADDR_FMT_plx"\n", start_addr); } } } @@ -642,8 +642,8 @@ static void xen_sync_dirty_bitmap(XenIOState *state, #endif if (errno == ENODATA) { memory_region_set_dirty(framebuffer, 0, size); - DPRINTF("xen: track_dirty_vram failed (0x" TARGET_FMT_plx - ", 0x" TARGET_FMT_plx "): %s\n", + DPRINTF("xen: track_dirty_vram failed (0x" HWADDR_FMT_plx + ", 0x" HWADDR_FMT_plx "): %s\n", start_addr, start_addr + size, strerror(errno)); } return; diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index a2f93096e7..1d0879d234 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -357,7 +357,7 @@ tryagain: entry->lock++; if (entry->lock == 0) { fprintf(stderr, - "mapcache entry lock overflow: "TARGET_FMT_plx" -> %p\n", + "mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p\n", entry->paddr_index, entry->vaddr_base); abort(); } @@ -404,7 +404,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr) if (!found) { fprintf(stderr, "%s, could not find %p\n", __func__, ptr); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - DPRINTF(" "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, + DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); } abort(); @@ -445,7 +445,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) if (!found) { DPRINTF("%s, could not find %p\n", __func__, buffer); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - DPRINTF(" "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); + DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); } return; } @@ -503,7 +503,7 @@ void xen_invalidate_map_cache(void) continue; } fprintf(stderr, "Locked DMA mapping while invalidating mapcache!" - " "TARGET_FMT_plx" -> %p is present\n", + " "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); } @@ -562,7 +562,7 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr, entry = entry->next; } if (!entry) { - DPRINTF("Trying to update an entry for "TARGET_FMT_plx \ + DPRINTF("Trying to update an entry for "HWADDR_FMT_plx \ "that is not in the mapcache!\n", old_phys_addr); return NULL; } @@ -570,15 +570,15 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr, address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT; address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1); - fprintf(stderr, "Replacing a dummy mapcache entry for "TARGET_FMT_plx \ - " with "TARGET_FMT_plx"\n", old_phys_addr, new_phys_addr); + fprintf(stderr, "Replacing a dummy mapcache entry for "HWADDR_FMT_plx \ + " with "HWADDR_FMT_plx"\n", old_phys_addr, new_phys_addr); xen_remap_bucket(entry, entry->vaddr_base, cache_size, address_index, false); if (!test_bits(address_offset >> XC_PAGE_SHIFT, test_bit_size >> XC_PAGE_SHIFT, entry->valid_mapping)) { - DPRINTF("Unable to update a mapcache entry for "TARGET_FMT_plx"!\n", + DPRINTF("Unable to update a mapcache entry for "HWADDR_FMT_plx"!\n", old_phys_addr); return NULL; } diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 7db0d94ec2..66e6de31a6 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -445,7 +445,7 @@ static uint64_t platform_mmio_read(void *opaque, hwaddr addr, unsigned size) { DPRINTF("Warning: attempted read from physical address " - "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr); + "0x" HWADDR_FMT_plx " in xen platform mmio space\n", addr); return 0; } @@ -454,7 +454,7 @@ static void platform_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical " - "address 0x" TARGET_FMT_plx " in xen platform mmio space\n", + "address 0x" HWADDR_FMT_plx " in xen platform mmio space\n", val, addr); } diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index d599fefcbc..35e850685c 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -564,7 +564,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, /* WO registers, return unknown value */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest read from WO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); *data = 0; return true; default: @@ -773,7 +773,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset, /* RO registers, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); return true; default: return false; @@ -838,7 +838,7 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, if (!r) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read at offset " TARGET_FMT_plx + "%s: invalid guest read at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_dist_badread(offset, size, attrs.secure); /* The spec requires that reserved registers are RAZ/WI; @@ -879,7 +879,7 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, if (!r) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write at offset " TARGET_FMT_plx + "%s: invalid guest write at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); /* The spec requires that reserved registers are RAZ/WI; diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 57c79da5c5..43dfd7a35c 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -1633,7 +1633,7 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset, /* RO register, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); } break; case GITS_CREADR + 4: @@ -1643,7 +1643,7 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset, /* RO register, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); } break; case GITS_BASER ... GITS_BASER + 0x3f: @@ -1675,7 +1675,7 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset, /* RO registers, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); break; default: result = false; @@ -1785,14 +1785,14 @@ static bool its_writell(GICv3ITSState *s, hwaddr offset, /* RO register, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); } break; case GITS_TYPER: /* RO registers, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); break; default: result = false; @@ -1851,7 +1851,7 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data, if (!result) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read at offset " TARGET_FMT_plx + "%s: invalid guest read at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_its_badread(offset, size); /* @@ -1887,7 +1887,7 @@ static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data, if (!result) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write at offset " TARGET_FMT_plx + "%s: invalid guest write at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_its_badwrite(offset, data, size); /* diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index c92ceecc16..297f7f0263 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -601,7 +601,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, /* RO registers, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); return MEMTX_OK; /* * VLPI frame registers. We don't need a version check for @@ -668,7 +668,7 @@ static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset, /* RO register, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); + HWADDR_FMT_plx "\n", __func__, offset); return MEMTX_OK; /* * VLPI frame registers. We don't need a version check for @@ -727,7 +727,7 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, if (r != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read at offset " TARGET_FMT_plx + "%s: invalid guest read at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset, size, attrs.secure); @@ -786,7 +786,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, if (r != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write at offset " TARGET_FMT_plx + "%s: invalid guest write at offset " HWADDR_FMT_plx " size %u\n", __func__, offset, size); trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data, size, attrs.secure); diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index a289510bdb..4ba448fdb1 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -120,7 +120,7 @@ exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size) default: if (offset >> 2 >= IIC_REGSET_SIZE) { hw_error("exynos4210.combiner: overflow of reg_set by 0x" - TARGET_FMT_plx "offset\n", offset); + HWADDR_FMT_plx "offset\n", offset); } val = s->reg_set[offset >> 2]; } @@ -184,19 +184,19 @@ static void exynos4210_combiner_write(void *opaque, hwaddr offset, if (req_quad_base_n >= IIC_NGRP) { hw_error("exynos4210.combiner: unallowed write access at offset 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return; } if (reg_n > 1) { hw_error("exynos4210.combiner: unallowed write access at offset 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); return; } if (offset >> 2 >= IIC_REGSET_SIZE) { hw_error("exynos4210.combiner: overflow of reg_set by 0x" - TARGET_FMT_plx "offset\n", offset); + HWADDR_FMT_plx "offset\n", offset); } s->reg_set[offset >> 2] = val; @@ -246,7 +246,7 @@ static void exynos4210_combiner_write(void *opaque, hwaddr offset, break; default: hw_error("exynos4210.combiner: unallowed write access at offset 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); break; } } diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 8a8012f5f0..28d50d9d09 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -299,7 +299,7 @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) s = AUX_SLAVE(dev); - monitor_printf(mon, "%*smemory " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", + monitor_printf(mon, "%*smemory " HWADDR_FMT_plx "/" HWADDR_FMT_plx "\n", indent, "", object_property_get_uint(OBJECT(s->mmio), "addr", NULL), memory_region_size(s->mmio)); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 8270db53cd..d66d912172 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -179,7 +179,7 @@ static void ivshmem_io_write(void *opaque, hwaddr addr, addr &= 0xfc; - IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr); + IVSHMEM_DPRINTF("writing to addr " HWADDR_FMT_plx "\n", addr); switch (addr) { case INTRMASK: @@ -207,7 +207,7 @@ static void ivshmem_io_write(void *opaque, hwaddr addr, } break; default: - IVSHMEM_DPRINTF("Unhandled write " TARGET_FMT_plx "\n", addr); + IVSHMEM_DPRINTF("Unhandled write " HWADDR_FMT_plx "\n", addr); } } @@ -233,7 +233,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr, break; default: - IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr); + IVSHMEM_DPRINTF("why are we reading " HWADDR_FMT_plx "\n", addr); ret = 0; } diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index efcc02609f..43bb1f56ba 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -704,7 +704,7 @@ static void dbdma_write(void *opaque, hwaddr addr, DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; - DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", + DBDMA_DPRINTFCH(ch, "writel 0x" HWADDR_FMT_plx " <= 0x%08"PRIx64"\n", addr, value); DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); @@ -786,7 +786,7 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr, break; } - DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); + DBDMA_DPRINTFCH(ch, "readl 0x" HWADDR_FMT_plx " => 0x%08x\n", addr, value); DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index 2aaadfa966..7692825867 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -131,7 +131,7 @@ mst_fpga_readb(void *opaque, hwaddr addr, unsigned size) return s->pcmcia1; default: printf("Mainstone - mst_fpga_readb: Bad register offset " - "0x" TARGET_FMT_plx "\n", addr); + "0x" HWADDR_FMT_plx "\n", addr); } return 0; } @@ -185,7 +185,7 @@ mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, break; default: printf("Mainstone - mst_fpga_writeb: Bad register offset " - "0x" TARGET_FMT_plx "\n", addr); + "0x" HWADDR_FMT_plx "\n", addr); } } diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index ecc0245fe8..b861d8ff35 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -663,7 +663,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, break; default: qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to unknown " - "EMAC register 0x" TARGET_FMT_plx "\n", + "EMAC register 0x" HWADDR_FMT_plx "\n", offset); } @@ -760,7 +760,7 @@ static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset, break; default: qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to unknown " - "EMAC register 0x" TARGET_FMT_plx "\n", + "EMAC register 0x" HWADDR_FMT_plx "\n", offset); } } diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index ddddf35c45..372e5b66da 100644 --- a/hw/net/allwinner_emac.c +++ b/hw/net/allwinner_emac.c @@ -304,7 +304,7 @@ static uint64_t aw_emac_read(void *opaque, hwaddr offset, unsigned size) default: qemu_log_mask(LOG_UNIMP, "allwinner_emac: read access to unknown register 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); ret = 0; } @@ -407,7 +407,7 @@ static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value, default: qemu_log_mask(LOG_UNIMP, "allwinner_emac: write access to unknown register 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); } } diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index b75d8e3dce..c753bfb3a8 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -99,7 +99,7 @@ static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size) break; } - DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx + DPRINTF("Read 0x%08x @ 0x" HWADDR_FMT_plx " : %s (%s)\n", ret, addr, reg->name, reg->desc); @@ -276,7 +276,7 @@ static void etsec_write(void *opaque, } } - DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx + DPRINTF("Write 0x%08x @ 0x" HWADDR_FMT_plx " val:0x%08x->0x%08x : %s (%s)\n", (unsigned int)value, addr, before, reg->value, reg->name, reg->desc); diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index a32589e33b..788463f1b6 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -109,7 +109,7 @@ static void read_buffer_descriptor(eTSEC *etsec, { assert(bd != NULL); - RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr); + RING_DEBUG("READ Buffer Descriptor @ 0x" HWADDR_FMT_plx"\n", addr); cpu_physical_memory_read(addr, bd, sizeof(eTSEC_rxtx_bd)); @@ -141,7 +141,7 @@ static void write_buffer_descriptor(eTSEC *etsec, stl_be_p(&bd->bufptr, bd->bufptr); } - RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr); + RING_DEBUG("Write Buffer Descriptor @ 0x" HWADDR_FMT_plx"\n", addr); cpu_physical_memory_write(addr, bd, sizeof(eTSEC_rxtx_bd)); diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index e63e524913..d456094575 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -908,11 +908,11 @@ static void pcnet_rdte_poll(PCNetState *s) s->csr[37] = nnrd >> 16; #ifdef PCNET_DEBUG if (bad) { - printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n", + printf("pcnet: BAD RMD RECORDS AFTER 0x" HWADDR_FMT_plx "\n", crda); } } else { - printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n", crda); + printf("pcnet: BAD RMD RDA=0x" HWADDR_FMT_plx "\n", crda); #endif } } diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index cf54ddf49d..7ea8eb6ba5 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -815,7 +815,7 @@ static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val) } break; default: - DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx + DPRINTF("not implemented dma reg write(l) addr=0x" HWADDR_FMT_plx " val=0x%08x (ring %d, addr=0x%02x)\n", addr, val, index, offset); break; @@ -857,7 +857,7 @@ static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val) r->lower32 = 0; break; default: - DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx + DPRINTF("not implemented write(l) addr=0x" HWADDR_FMT_plx " val=0x%08x\n", addr, val); break; } @@ -876,8 +876,8 @@ static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val) desc_ring_set_base_addr(r->rings[index], val); break; default: - DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx - " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n", + DPRINTF("not implemented dma reg write(q) addr=0x" HWADDR_FMT_plx + " val=0x" HWADDR_FMT_plx " (ring %d, offset=0x%02x)\n", addr, val, index, offset); break; } @@ -895,8 +895,8 @@ static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val) rocker_port_phys_enable_write(r, val); break; default: - DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx - " val=0x" TARGET_FMT_plx "\n", addr, val); + DPRINTF("not implemented write(q) addr=0x" HWADDR_FMT_plx + " val=0x" HWADDR_FMT_plx "\n", addr, val); break; } } @@ -987,8 +987,8 @@ static const char *rocker_reg_name(void *opaque, hwaddr addr) static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - DPRINTF("Write %s addr " TARGET_FMT_plx - ", size %u, val " TARGET_FMT_plx "\n", + DPRINTF("Write %s addr " HWADDR_FMT_plx + ", size %u, val " HWADDR_FMT_plx "\n", rocker_reg_name(opaque, addr), addr, size, val); switch (size) { @@ -1060,7 +1060,7 @@ static uint32_t rocker_io_readl(void *opaque, hwaddr addr) ret = desc_ring_get_credits(r->rings[index]); break; default: - DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx + DPRINTF("not implemented dma reg read(l) addr=0x" HWADDR_FMT_plx " (ring %d, addr=0x%02x)\n", addr, index, offset); ret = 0; break; @@ -1115,7 +1115,7 @@ static uint32_t rocker_io_readl(void *opaque, hwaddr addr) ret = (uint32_t)(r->switch_id >> 32); break; default: - DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr); + DPRINTF("not implemented read(l) addr=0x" HWADDR_FMT_plx "\n", addr); ret = 0; break; } @@ -1136,7 +1136,7 @@ static uint64_t rocker_io_readq(void *opaque, hwaddr addr) ret = desc_ring_get_base_addr(r->rings[index]); break; default: - DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx + DPRINTF("not implemented dma reg read(q) addr=0x" HWADDR_FMT_plx " (ring %d, addr=0x%02x)\n", addr, index, offset); ret = 0; break; @@ -1165,7 +1165,7 @@ static uint64_t rocker_io_readq(void *opaque, hwaddr addr) ret = r->switch_id; break; default: - DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr); + DPRINTF("not implemented read(q) addr=0x" HWADDR_FMT_plx "\n", addr); ret = 0; break; } @@ -1174,7 +1174,7 @@ static uint64_t rocker_io_readq(void *opaque, hwaddr addr) static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size) { - DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n", + DPRINTF("Read %s addr " HWADDR_FMT_plx ", size %u\n", rocker_reg_name(opaque, addr), addr, size); switch (size) { diff --git a/hw/net/rocker/rocker_desc.c b/hw/net/rocker/rocker_desc.c index f3068c9250..675383db36 100644 --- a/hw/net/rocker/rocker_desc.c +++ b/hw/net/rocker/rocker_desc.c @@ -104,7 +104,7 @@ static bool desc_ring_empty(DescRing *ring) bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr) { if (base_addr & 0x7) { - DPRINTF("ERROR: ring[%d] desc base addr (0x" TARGET_FMT_plx + DPRINTF("ERROR: ring[%d] desc base addr (0x" HWADDR_FMT_plx ") not 8-byte aligned\n", ring->index, base_addr); return false; } diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 990ff3a1c2..7e00965323 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -524,7 +524,7 @@ static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) if (addr < ARRAY_SIZE(s->regs)) { r = s->regs[addr]; } - DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", + DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n", __func__, addr * 4, r)); break; } @@ -630,7 +630,7 @@ static void enet_write(void *opaque, hwaddr addr, break; default: - DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", + DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n", __func__, addr * 4, (unsigned)value)); if (addr < ARRAY_SIZE(s->regs)) { s->regs[addr] = value; diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 6e09f7e422..99c22819ea 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -99,7 +99,7 @@ eth_read(void *opaque, hwaddr addr, unsigned int size) case R_RX_CTRL1: case R_RX_CTRL0: r = s->regs[addr]; - D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r)); + D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr * 4, r)); break; default: @@ -125,7 +125,7 @@ eth_write(void *opaque, hwaddr addr, if (addr == R_TX_CTRL1) base = 0x800 / 4; - D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n", __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { qemu_send_packet(qemu_get_queue(s->nic), @@ -155,7 +155,7 @@ eth_write(void *opaque, hwaddr addr, case R_TX_LEN0: case R_TX_LEN1: case R_TX_GIE0: - D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + D(qemu_log("%s addr=" HWADDR_FMT_plx " val=%x\n", __func__, addr * 4, value)); s->regs[addr] = value; break; diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 870d9bab11..e752a21292 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -155,7 +155,7 @@ static char *pxb_host_ofw_unit_address(const SysBusDevice *dev) main_host_sbd = SYS_BUS_DEVICE(main_host); if (main_host_sbd->num_mmio > 0) { - return g_strdup_printf(TARGET_FMT_plx ",%x", + return g_strdup_printf(HWADDR_FMT_plx ",%x", main_host_sbd->mmio[0].addr, position + 1); } if (main_host_sbd->num_pio > 0) { diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index ac1eebf9de..1cf25bab8d 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -251,7 +251,7 @@ static void bonito_writel(void *opaque, hwaddr addr, saddr = addr >> 2; - DPRINTF("bonito_writel "TARGET_FMT_plx" val %lx saddr %x\n", + DPRINTF("bonito_writel "HWADDR_FMT_plx" val %lx saddr %x\n", addr, val, saddr); switch (saddr) { case BONITO_BONPONCFG: @@ -314,7 +314,7 @@ static uint64_t bonito_readl(void *opaque, hwaddr addr, saddr = addr >> 2; - DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr); + DPRINTF("bonito_readl "HWADDR_FMT_plx"\n", addr); switch (saddr) { case BONITO_INTISR: return s->regs[saddr]; @@ -339,7 +339,7 @@ static void bonito_pciconf_writel(void *opaque, hwaddr addr, PCIBonitoState *s = opaque; PCIDevice *d = PCI_DEVICE(s); - DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %lx\n", addr, val); + DPRINTF("bonito_pciconf_writel "HWADDR_FMT_plx" val %lx\n", addr, val); d->config_write(d, addr, val, 4); } @@ -350,7 +350,7 @@ static uint64_t bonito_pciconf_readl(void *opaque, hwaddr addr, PCIBonitoState *s = opaque; PCIDevice *d = PCI_DEVICE(s); - DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr); + DPRINTF("bonito_pciconf_readl "HWADDR_FMT_plx"\n", addr); return d->config_read(d, addr, 4); } @@ -466,7 +466,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr) regno = (cfgaddr & BONITO_PCICONF_REG_MASK_HW) >> BONITO_PCICONF_REG_OFFSET; if (idsel == 0) { - error_report("error in bonito pci config address 0x" TARGET_FMT_plx + error_report("error in bonito pci config address 0x" HWADDR_FMT_plx ",pcimap_cfg=0x%x", addr, s->regs[BONITO_PCIMAP_CFG]); exit(1); } @@ -486,7 +486,7 @@ static void bonito_spciconf_write(void *opaque, hwaddr addr, uint64_t val, uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_write "TARGET_FMT_plx" size %d val %lx\n", + DPRINTF("bonito_spciconf_write "HWADDR_FMT_plx" size %d val %lx\n", addr, size, val); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -516,7 +516,7 @@ static uint64_t bonito_spciconf_read(void *opaque, hwaddr addr, unsigned size) uint32_t pciaddr; uint16_t status; - DPRINTF("bonito_spciconf_read "TARGET_FMT_plx" size %d\n", addr, size); + DPRINTF("bonito_spciconf_read "HWADDR_FMT_plx" size %d\n", addr, size); pciaddr = bonito_sbridge_pciaddr(s, addr); diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 568849e930..38814247f2 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -189,7 +189,7 @@ static uint64_t pci_reg_read4(void *opaque, hwaddr addr, break; } - pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__, + pci_debug("%s: win:%lx(addr:" HWADDR_FMT_plx ") -> value:%x\n", __func__, win, addr, value); return value; } @@ -268,7 +268,7 @@ static void pci_reg_write4(void *opaque, hwaddr addr, win = addr & 0xfe0; - pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n", + pci_debug("%s: value:%x -> win:%lx(addr:" HWADDR_FMT_plx ")\n", __func__, (unsigned)value, win, addr); switch (win) { diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index ead1d3e61c..dfd185bbb4 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -149,7 +149,7 @@ static void pci_host_config_write(void *opaque, hwaddr addr, { PCIHostState *s = opaque; - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", + PCI_DPRINTF("%s addr " HWADDR_FMT_plx " len %d val %"PRIx64"\n", __func__, addr, len, val); if (addr != 0 || len != 4) { return; @@ -163,7 +163,7 @@ static uint64_t pci_host_config_read(void *opaque, hwaddr addr, PCIHostState *s = opaque; uint32_t val = s->config_reg; - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n", + PCI_DPRINTF("%s addr " HWADDR_FMT_plx " len %d val %"PRIx32"\n", __func__, addr, len, val); return val; } diff --git a/hw/ppc/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c index a24c80b1d2..4501fb28a5 100644 --- a/hw/ppc/ppc4xx_sdram.c +++ b/hw/ppc/ppc4xx_sdram.c @@ -500,7 +500,7 @@ static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size) bcr = 0x8000; break; default: - error_report("invalid RAM size " TARGET_FMT_plx, ram_size); + error_report("invalid RAM size " HWADDR_FMT_plx, ram_size); return 0; } bcr |= ram_base >> 2 & 0xffe00000; diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c index d1620c7a2a..2b8a38a296 100644 --- a/hw/rtc/exynos4210_rtc.c +++ b/hw/rtc/exynos4210_rtc.c @@ -374,7 +374,7 @@ static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_GUEST_ERROR, - "exynos4210.rtc: bad read offset " TARGET_FMT_plx, + "exynos4210.rtc: bad read offset " HWADDR_FMT_plx, offset); break; } @@ -508,7 +508,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_GUEST_ERROR, - "exynos4210.rtc: bad write offset " TARGET_FMT_plx, + "exynos4210.rtc: bad write offset " HWADDR_FMT_plx, offset); break; diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index c77792d150..ebe0fd96d9 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -207,13 +207,13 @@ static void portb_changed(SH7750State *s, uint16_t prev) static void error_access(const char *kind, hwaddr addr) { - fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", + fprintf(stderr, "%s to %s (0x" HWADDR_FMT_plx ") not supported\n", kind, regname(addr), addr); } static void ignore_access(const char *kind, hwaddr addr) { - fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", + fprintf(stderr, "%s to %s (0x" HWADDR_FMT_plx ") ignored\n", kind, regname(addr), addr); } diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index b2819a7ff0..552927622f 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -232,7 +232,7 @@ spi_read(void *opaque, hwaddr addr, unsigned int size) break; } - DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r); + DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr * 4, r); xlx_spi_update_irq(s); return r; } @@ -244,7 +244,7 @@ spi_write(void *opaque, hwaddr addr, XilinxSPI *s = opaque; uint32_t value = val64; - DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value); + DB_PRINT("addr=" HWADDR_FMT_plx " = %x\n", addr, value); addr >>= 2; switch (addr) { case R_SRR: diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 1e9dba2039..97009d3a5d 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -887,7 +887,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, case R_INTR_STATUS: ret = s->regs[addr] & IXR_ALL; s->regs[addr] = 0; - DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + DB_PRINT_L(0, "addr=" HWADDR_FMT_plx " = %x\n", addr * 4, ret); xilinx_spips_update_ixr(s); return ret; case R_INTR_MASK: @@ -916,12 +916,12 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, if (!(s->regs[R_CONFIG] & R_CONFIG_ENDIAN)) { ret <<= 8 * shortfall; } - DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + DB_PRINT_L(0, "addr=" HWADDR_FMT_plx " = %x\n", addr * 4, ret); xilinx_spips_check_flush(s); xilinx_spips_update_ixr(s); return ret; } - DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, + DB_PRINT_L(0, "addr=" HWADDR_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask); return s->regs[addr] & mask; @@ -971,7 +971,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, XilinxSPIPS *s = opaque; bool try_flush = true; - DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); + DB_PRINT_L(0, "addr=" HWADDR_FMT_plx " = %x\n", addr, (unsigned)value); addr >>= 2; switch (addr) { case R_CONFIG: diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index d5186f4454..973eab4386 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -76,7 +76,7 @@ static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size) default: qemu_log_mask(LOG_UNIMP, "digic-timer: read access to unknown register 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); } return ret; @@ -116,7 +116,7 @@ static void digic_timer_write(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_UNIMP, "digic-timer: read access to unknown register 0x" - TARGET_FMT_plx "\n", offset); + HWADDR_FMT_plx "\n", offset); } } diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index ecc2831baf..2d6d92ef93 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -324,8 +324,7 @@ timer_write(void *opaque, hwaddr addr, t->rw_ack_intr = 0; break; default: - printf ("%s " TARGET_FMT_plx " %x\n", - __func__, addr, value); + printf("%s " HWADDR_FMT_plx " %x\n", __func__, addr, value); break; } } diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index e175a9f5b9..c17b247da3 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1445,7 +1445,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case L0_ICNTO: case L1_ICNTO: case L0_FRCNTO: case L1_FRCNTO: qemu_log_mask(LOG_GUEST_ERROR, - "exynos4210.mct: write to RO register " TARGET_FMT_plx, + "exynos4210.mct: write to RO register " HWADDR_FMT_plx, offset); break; diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 02924a9e5b..3528d0f33a 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -257,7 +257,7 @@ static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_GUEST_ERROR, - "exynos4210.pwm: bad read offset " TARGET_FMT_plx, + "exynos4210.pwm: bad read offset " HWADDR_FMT_plx, offset); break; } @@ -352,7 +352,7 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset, default: qemu_log_mask(LOG_GUEST_ERROR, - "exynos4210.pwm: bad write offset " TARGET_FMT_plx, + "exynos4210.pwm: bad write offset " HWADDR_FMT_plx, offset); break; diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 103260ec15..23ba625eb6 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -829,10 +829,10 @@ static char *virtio_mmio_bus_get_dev_path(DeviceState *dev) assert(section.mr); if (proxy_path) { - path = g_strdup_printf("%s/virtio-mmio@" TARGET_FMT_plx, proxy_path, + path = g_strdup_printf("%s/virtio-mmio@" HWADDR_FMT_plx, proxy_path, section.offset_within_address_space); } else { - path = g_strdup_printf("virtio-mmio@" TARGET_FMT_plx, + path = g_strdup_printf("virtio-mmio@" HWADDR_FMT_plx, section.offset_within_address_space); } memory_region_unref(section.mr); diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 0ec7e52183..8db0532632 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -434,7 +434,7 @@ static uint64_t xen_pt_bar_read(void *o, hwaddr addr, PCIDevice *d = o; /* if this function is called, that probably means that there is a * misconfiguration of the IOMMU. */ - XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n", + XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"HWADDR_FMT_plx"\n", addr); return 0; } @@ -443,7 +443,7 @@ static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val, { PCIDevice *d = o; /* Same comment as xen_pt_bar_read function */ - XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n", + XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"HWADDR_FMT_plx"\n", addr); } diff --git a/include/exec/hwaddr.h b/include/exec/hwaddr.h index 8f16d179a8..50fbb2d96c 100644 --- a/include/exec/hwaddr.h +++ b/include/exec/hwaddr.h @@ -10,7 +10,7 @@ typedef uint64_t hwaddr; #define HWADDR_MAX UINT64_MAX -#define TARGET_FMT_plx "%016" PRIx64 +#define HWADDR_FMT_plx "%016" PRIx64 #define HWADDR_PRId PRId64 #define HWADDR_PRIi PRIi64 #define HWADDR_PRIo PRIo64 diff --git a/monitor/misc.c b/monitor/misc.c index bf3f1c67ca..fa0a42c261 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -566,7 +566,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, while (len > 0) { if (is_physical) { - monitor_printf(mon, TARGET_FMT_plx ":", addr); + monitor_printf(mon, HWADDR_FMT_plx ":", addr); } else { monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr); } diff --git a/softmmu/memory.c b/softmmu/memory.c index e05332d07f..9d64efca26 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -1281,7 +1281,7 @@ static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, unsigned size) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); + printf("Unassigned mem read " HWADDR_FMT_plx "\n", addr); #endif return 0; } @@ -1290,7 +1290,7 @@ static void unassigned_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val); + printf("Unassigned mem write " HWADDR_FMT_plx " = 0x%"PRIx64"\n", addr, val); #endif } @@ -3220,9 +3220,9 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, for (i = 0; i < level; i++) { qemu_printf(MTREE_INDENT); } - qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx - " (prio %d, %s%s): alias %s @%s " TARGET_FMT_plx - "-" TARGET_FMT_plx "%s", + qemu_printf(HWADDR_FMT_plx "-" HWADDR_FMT_plx + " (prio %d, %s%s): alias %s @%s " HWADDR_FMT_plx + "-" HWADDR_FMT_plx "%s", cur_start, cur_end, mr->priority, mr->nonvolatile ? "nv-" : "", @@ -3242,7 +3242,7 @@ static void mtree_print_mr(const MemoryRegion *mr, unsigned int level, for (i = 0; i < level; i++) { qemu_printf(MTREE_INDENT); } - qemu_printf(TARGET_FMT_plx "-" TARGET_FMT_plx + qemu_printf(HWADDR_FMT_plx "-" HWADDR_FMT_plx " (prio %d, %s%s): %s%s", cur_start, cur_end, mr->priority, @@ -3329,8 +3329,8 @@ static void mtree_print_flatview(gpointer key, gpointer value, while (n--) { mr = range->mr; if (range->offset_in_region) { - qemu_printf(MTREE_INDENT TARGET_FMT_plx "-" TARGET_FMT_plx - " (prio %d, %s%s): %s @" TARGET_FMT_plx, + qemu_printf(MTREE_INDENT HWADDR_FMT_plx "-" HWADDR_FMT_plx + " (prio %d, %s%s): %s @" HWADDR_FMT_plx, int128_get64(range->addr.start), int128_get64(range->addr.start) + MR_SIZE(range->addr.size), @@ -3340,7 +3340,7 @@ static void mtree_print_flatview(gpointer key, gpointer value, memory_region_name(mr), range->offset_in_region); } else { - qemu_printf(MTREE_INDENT TARGET_FMT_plx "-" TARGET_FMT_plx + qemu_printf(MTREE_INDENT HWADDR_FMT_plx "-" HWADDR_FMT_plx " (prio %d, %s%s): %s", int128_get64(range->addr.start), int128_get64(range->addr.start) diff --git a/softmmu/memory_mapping.c b/softmmu/memory_mapping.c index f6f0a829fd..d7f1d096e0 100644 --- a/softmmu/memory_mapping.c +++ b/softmmu/memory_mapping.c @@ -241,8 +241,8 @@ static void guest_phys_block_add_section(GuestPhysListener *g, } #ifdef DEBUG_GUEST_PHYS_REGION_ADD - fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end=" - TARGET_FMT_plx ": %s (count: %u)\n", __func__, target_start, + fprintf(stderr, "%s: target_start=" HWADDR_FMT_plx " target_end=" + HWADDR_FMT_plx ": %s (count: %u)\n", __func__, target_start, target_end, predecessor ? "joined" : "added", g->list->num); #endif } diff --git a/softmmu/physmem.c b/softmmu/physmem.c index edec095c7a..bf585e45a8 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -2475,7 +2475,7 @@ static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data, MemTxResult res; #if defined(DEBUG_SUBPAGE) - printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__, + printf("%s: subpage %p len %u addr " HWADDR_FMT_plx "\n", __func__, subpage, len, addr); #endif res = flatview_read(subpage->fv, addr + subpage->base, attrs, buf, len); @@ -2493,7 +2493,7 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr, uint8_t buf[8]; #if defined(DEBUG_SUBPAGE) - printf("%s: subpage %p len %u addr " TARGET_FMT_plx + printf("%s: subpage %p len %u addr " HWADDR_FMT_plx " value %"PRIx64"\n", __func__, subpage, len, addr, value); #endif @@ -2507,7 +2507,7 @@ static bool subpage_accepts(void *opaque, hwaddr addr, { subpage_t *subpage = opaque; #if defined(DEBUG_SUBPAGE) - printf("%s: subpage %p %c len %u addr " TARGET_FMT_plx "\n", + printf("%s: subpage %p %c len %u addr " HWADDR_FMT_plx "\n", __func__, subpage, is_write ? 'w' : 'r', len, addr); #endif @@ -2558,7 +2558,7 @@ static subpage_t *subpage_init(FlatView *fv, hwaddr base) NULL, TARGET_PAGE_SIZE); mmio->iomem.subpage = true; #if defined(DEBUG_SUBPAGE) - printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__, + printf("%s: %p base " HWADDR_FMT_plx " len %08x\n", __func__, mmio, base, TARGET_PAGE_SIZE); #endif @@ -3703,7 +3703,7 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root) const char *names[] = { " [unassigned]", " [not dirty]", " [ROM]", " [watch]" }; - qemu_printf(" #%d @" TARGET_FMT_plx ".." TARGET_FMT_plx + qemu_printf(" #%d @" HWADDR_FMT_plx ".." HWADDR_FMT_plx " %s%s%s%s%s", i, s->offset_within_address_space, diff --git a/target/i386/monitor.c b/target/i386/monitor.c index 8e4b4d600c..ad5b7b8bb5 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -57,7 +57,7 @@ static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr, { addr = addr_canonical(env, addr); - monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx + monitor_printf(mon, HWADDR_FMT_plx ": " HWADDR_FMT_plx " %c%c%c%c%c%c%c%c%c\n", addr, pte & mask, @@ -258,8 +258,8 @@ static void mem_print(Monitor *mon, CPUArchState *env, prot1 = *plast_prot; if (prot != prot1) { if (*pstart != -1) { - monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " " - TARGET_FMT_plx " %c%c%c\n", + monitor_printf(mon, HWADDR_FMT_plx "-" HWADDR_FMT_plx " " + HWADDR_FMT_plx " %c%c%c\n", addr_canonical(env, *pstart), addr_canonical(env, end), addr_canonical(env, end - *pstart), diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index c6d1de50fe..cce1db1e0a 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -655,7 +655,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, physical & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); qemu_log_mask(CPU_LOG_MMU, - "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx + "%s address=%" VADDR_PRIx " physical " HWADDR_FMT_plx " prot %d\n", __func__, address, physical, prot); return true; } else { diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 5b745d0928..f6378030b7 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -403,7 +403,7 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, CPUMBState *env = &cpu->env; qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx - " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n", + " 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")); diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index 9d16859c0a..e5e1e9dd3f 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -924,7 +924,7 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, switch (ret) { case TLBRET_MATCH: qemu_log_mask(CPU_LOG_MMU, - "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx + "%s address=%" VADDR_PRIx " physical " HWADDR_FMT_plx " prot %d\n", __func__, address, physical, prot); break; default: diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index cc091c3e62..3976416840 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -346,24 +346,24 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu, ptem = (vsid << 7) | (pgidx >> 10); /* Page address translation */ - qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx - " htab_mask " TARGET_FMT_plx - " hash " TARGET_FMT_plx "\n", + qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx + " htab_mask " HWADDR_FMT_plx + " hash " HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); /* Primary PTEG lookup */ - qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx " vsid=%" PRIx32 " ptem=%" PRIx32 - " hash=" TARGET_FMT_plx "\n", + " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), vsid, ptem, hash); pteg_off = get_pteg_offset32(cpu, hash); pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte); if (pte_offset == -1) { /* Secondary PTEG lookup */ - qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx " vsid=%" PRIx32 " api=%" PRIx32 - " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu), + " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash); pteg_off = get_pteg_offset32(cpu, ~hash); pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte); diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index b9b31fd276..900f906990 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -697,15 +697,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu, /* Page address translation */ qemu_log_mask(CPU_LOG_MMU, - "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx - " hash " TARGET_FMT_plx "\n", + "htab_base " HWADDR_FMT_plx " htab_mask " HWADDR_FMT_plx + " hash " HWADDR_FMT_plx "\n", ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash); /* Primary PTEG lookup */ qemu_log_mask(CPU_LOG_MMU, - "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", + " hash=" HWADDR_FMT_plx "\n", ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), vsid, ptem, hash); ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift); @@ -714,9 +714,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu, /* Secondary PTEG lookup */ ptem |= HPTE64_V_SECONDARY; qemu_log_mask(CPU_LOG_MMU, - "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu), + " hash=" HWADDR_FMT_plx "\n", ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash); ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift); diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 8901f4d134..7235a4befe 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -252,7 +252,7 @@ static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, } if (best != -1) { done: - qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); /* Update page flags */ @@ -328,7 +328,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, ctx->prot = prot; ret = check_prot(ctx->prot, access_type); if (ret == 0) { - qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); @@ -403,9 +403,9 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ - qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx - " htab_mask " TARGET_FMT_plx - " hash " TARGET_FMT_plx "\n", + qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx + " htab_mask " HWADDR_FMT_plx + " hash " HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); ctx->hash[0] = hash; ctx->hash[1] = ~hash; @@ -420,7 +420,7 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, hwaddr curaddr; uint32_t a0, a1, a2, a3; - qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx + qemu_log("Page table: " HWADDR_FMT_plx " len " HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu) + 0x80); for (curaddr = ppc_hash32_hpt_base(cpu); @@ -432,7 +432,7 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, a2 = ldl_phys(cs->as, curaddr + 8); a3 = ldl_phys(cs->as, curaddr + 12); if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { - qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n", + qemu_log(HWADDR_FMT_plx ": %08x %08x %08x %08x\n", curaddr, a0, a1, a2, a3); } } @@ -578,14 +578,14 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, if (ret >= 0) { ctx->raddr = raddr; qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx - " => " TARGET_FMT_plx + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); return 0; } } qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx - " => " TARGET_FMT_plx + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, raddr, ctx->prot, ret); return ret; @@ -666,11 +666,11 @@ static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, if (ret >= 0) { ctx->raddr = raddr; qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx - " => " TARGET_FMT_plx " %d %d\n", __func__, + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); } else { qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx - " => " TARGET_FMT_plx " %d %d\n", __func__, + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, raddr, ctx->prot, ret); } @@ -894,11 +894,11 @@ found_tlb: if (ret >= 0) { ctx->raddr = raddr; qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx - " => " TARGET_FMT_plx " %d %d\n", __func__, address, + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); } else { qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx - " => " TARGET_FMT_plx " %d %d\n", __func__, address, + " => " HWADDR_FMT_plx " %d %d\n", __func__, address, raddr, ctx->prot, ret); } diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 2a91f3f46a..64e30435f5 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -826,7 +826,7 @@ void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry, tlb->prot &= ~PAGE_VALID; } tlb->PID = env->spr[SPR_40x_PID]; /* PID */ - qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " HWADDR_FMT_plx " EPN " TARGET_FMT_lx " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, (int)entry, tlb->RPN, tlb->EPN, tlb->size, @@ -864,7 +864,7 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry, if (val & PPC4XX_TLBLO_WR) { tlb->prot |= PAGE_WRITE; } - qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " HWADDR_FMT_plx " EPN " TARGET_FMT_lx " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__, (int)entry, tlb->RPN, tlb->EPN, tlb->size, diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 8ea3442b4a..9a28816521 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1272,7 +1272,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, qemu_log_mask(CPU_LOG_MMU, "%s 1st-stage address=%" VADDR_PRIx " ret %d physical " - TARGET_FMT_plx " prot %d\n", + HWADDR_FMT_plx " prot %d\n", __func__, address, ret, pa, prot); if (ret == TRANSLATE_SUCCESS) { @@ -1285,7 +1285,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, qemu_log_mask(CPU_LOG_MMU, "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical " - TARGET_FMT_plx " prot %d\n", + HWADDR_FMT_plx " prot %d\n", __func__, im_address, ret, pa, prot2); prot &= prot2; @@ -1295,7 +1295,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, size, access_type, mode); qemu_log_mask(CPU_LOG_MMU, - "%s PMP address=" TARGET_FMT_plx " ret %d prot" + "%s PMP address=" HWADDR_FMT_plx " ret %d prot" " %d tlb_size " TARGET_FMT_lu "\n", __func__, pa, ret, prot_pmp, tlb_size); @@ -1320,7 +1320,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, qemu_log_mask(CPU_LOG_MMU, "%s address=%" VADDR_PRIx " ret %d physical " - TARGET_FMT_plx " prot %d\n", + HWADDR_FMT_plx " prot %d\n", __func__, address, ret, pa, prot); if (ret == TRANSLATE_SUCCESS) { @@ -1328,7 +1328,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, size, access_type, mode); qemu_log_mask(CPU_LOG_MMU, - "%s PMP address=" TARGET_FMT_plx " ret %d prot" + "%s PMP address=" HWADDR_FMT_plx " ret %d prot" " %d tlb_size " TARGET_FMT_lu "\n", __func__, pa, ret, prot_pmp, tlb_size); diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index 17e63fab00..236f93b9f5 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -64,7 +64,7 @@ static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr, return; } - monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx + monitor_printf(mon, TARGET_FMT_lx " " HWADDR_FMT_plx " " TARGET_FMT_lx " %c%c%c%c%c%c%c\n", addr_canonical(va_bits, vaddr), paddr, size, diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index ec4fae78c3..a53580d9e4 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -430,12 +430,12 @@ static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr, #ifdef DEBUG_UNASSIGNED if (is_asi) { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + printf("Unassigned mem %s access of %d byte%s to " HWADDR_FMT_plx " asi 0x%02x from " TARGET_FMT_lx "\n", is_exec ? "exec" : is_write ? "write" : "read", size, size == 1 ? "" : "s", addr, is_asi, env->pc); } else { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + printf("Unassigned mem %s access of %d byte%s to " HWADDR_FMT_plx " from " TARGET_FMT_lx "\n", is_exec ? "exec" : is_write ? "write" : "read", size, size == 1 ? "" : "s", addr, env->pc); @@ -490,7 +490,7 @@ static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr, CPUSPARCState *env = &cpu->env; #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx + printf("Unassigned mem access to " HWADDR_FMT_plx " from " TARGET_FMT_lx "\n", addr, env->pc); #endif diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 919448a494..158ec2ae8f 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -230,7 +230,7 @@ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (likely(error_code == 0)) { qemu_log_mask(CPU_LOG_MMU, "Translate at %" VADDR_PRIx " -> " - TARGET_FMT_plx ", vaddr " TARGET_FMT_lx "\n", + HWADDR_FMT_plx ", vaddr " TARGET_FMT_lx "\n", address, paddr, vaddr); tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); return true; @@ -356,27 +356,27 @@ void dump_mmu(CPUSPARCState *env) hwaddr pa; uint32_t pde; - qemu_printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", + qemu_printf("Root ptr: " HWADDR_FMT_plx ", ctx: %d\n", (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { pde = mmu_probe(env, va, 2); if (pde) { pa = cpu_get_phys_page_debug(cs, va); - qemu_printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + qemu_printf("VA: " TARGET_FMT_lx ", PA: " HWADDR_FMT_plx " PDE: " TARGET_FMT_lx "\n", va, pa, pde); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { pde = mmu_probe(env, va1, 1); if (pde) { pa = cpu_get_phys_page_debug(cs, va1); qemu_printf(" VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", + HWADDR_FMT_plx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { pde = mmu_probe(env, va2, 0); if (pde) { pa = cpu_get_phys_page_debug(cs, va2); qemu_printf(" VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PTE: " + HWADDR_FMT_plx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde); } diff --git a/target/tricore/helper.c b/target/tricore/helper.c index 1db32808e8..114685cce4 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -79,7 +79,7 @@ bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size, address, rw, mmu_idx); qemu_log_mask(CPU_LOG_MMU, "%s address=" TARGET_FMT_lx " ret %d physical " - TARGET_FMT_plx " prot %d\n", + HWADDR_FMT_plx " prot %d\n", __func__, (target_ulong)address, ret, physical, prot); if (ret == TLBRET_MATCH) { From 736eca5f680dba690b8efef264d61f4d927d9ecd Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 13 Jan 2023 09:17:35 +0100 Subject: [PATCH 099/814] MAINTAINERS: Remove bouncing mail address from Kamil Rytarowski When sending mail to Kamil's address, it's bouncing with a message that the mailbox is full. This already happens since summer 2022, and the last message that Kamil sent to the qemu-devel mailing list is from November 2021 (as far as I can see), so we unfortunately have to assume that this e-mail address is not valid anymore. Message-Id: <20230113081735.1148057-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0fe50d01e3..08ad1e5341 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -511,7 +511,6 @@ F: target/i386/hax/ Guest CPU Cores (NVMM) ---------------------- NetBSD Virtual Machine Monitor (NVMM) CPU support -M: Kamil Rytarowski M: Reinoud Zandijk S: Maintained F: include/sysemu/nvmm.h @@ -536,7 +535,6 @@ F: util/*posix*.c F: include/qemu/*posix*.h NETBSD -M: Kamil Rytarowski M: Reinoud Zandijk M: Ryo ONODERA S: Maintained From db2237c459c3bdeb058ff66d7708a4a61ea8fa1c Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Fri, 13 Jan 2023 11:04:13 -0300 Subject: [PATCH 100/814] tests/qtest: Restrict bcm2835-dma-test to CONFIG_RASPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will soon enable the build without TCG, which does not support many machines, so only run the bcm2835-dma-test when the corresponding machine is present. Signed-off-by: Fabiano Rosas Message-Id: <20230113140419.4013-23-farosas@suse.de> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index f0ebb5fac6..1af63f8bd2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -207,11 +207,11 @@ qtests_aarch64 = \ (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) + \ (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ (config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \ + (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \ ['arm-cpu-features', 'numa-test', 'boot-serial-test', - 'migration-test', - 'bcm2835-dma-test'] + 'migration-test'] qtests_s390x = \ (slirp.found() ? ['pxe-test', 'test-netfilter'] : []) + \ From da994bac07b486b5c5dc50ee411ba0bcf9f95e1e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 14 Jan 2023 12:59:18 +0900 Subject: [PATCH 101/814] tests/qtest/e1000e-test: Fix the code style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit igb implementation first starts off by copying e1000e code. Correct the code style before that. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230114035919.35251-19-akihiko.odaki@daynix.com> Signed-off-by: Thomas Huth --- tests/qtest/e1000e-test.c | 2 +- tests/qtest/libqos/e1000e.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c index 3fc92046be..b63a4d3c91 100644 --- a/tests/qtest/e1000e-test.c +++ b/tests/qtest/e1000e-test.c @@ -1,4 +1,4 @@ - /* +/* * QTest testcase for e1000e NIC * * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c index 37c794b130..b90eb2d5e0 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -222,8 +222,10 @@ static void e1000e_register_nodes(void) .device_id = E1000_DEV_ID_82574L, }; - /* FIXME: every test using this node needs to setup a -netdev socket,id=hs0 - * otherwise QEMU is not going to start */ + /* + * FIXME: every test using this node needs to setup a -netdev socket,id=hs0 + * otherwise QEMU is not going to start + */ QOSGraphEdgeOptions opts = { .extra_device_opts = "netdev=hs0", }; From 57b8d8d6c20f85f53bb3d4ad3bb3ec03e942f05c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 14 Jan 2023 12:59:19 +0900 Subject: [PATCH 102/814] tests/qtest/libqos/e1000e: Remove duplicate register definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The register definitions in tests/qtest/libqos/e1000e.h had names different from hw/net/e1000_regs.h, which made it hard to understand what test codes corresponds to the implementation. Use hw/net/e1000_regs.h from tests/qtest/libqos/e1000e.c to remove these duplications. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230114035919.35251-20-akihiko.odaki@daynix.com> Signed-off-by: Thomas Huth --- tests/qtest/libqos/e1000e.c | 20 ++++++++++---------- tests/qtest/libqos/e1000e.h | 5 ----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c index b90eb2d5e0..28fb3052aa 100644 --- a/tests/qtest/libqos/e1000e.c +++ b/tests/qtest/libqos/e1000e.c @@ -51,13 +51,13 @@ static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg) void e1000e_tx_ring_push(QE1000E *d, void *descr) { QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - uint32_t tail = e1000e_macreg_read(d, E1000E_TDT); - uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000_RING_DESC_LEN; + uint32_t tail = e1000e_macreg_read(d, E1000_TDT); + uint32_t len = e1000e_macreg_read(d, E1000_TDLEN) / E1000_RING_DESC_LEN; qtest_memwrite(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000_RING_DESC_LEN, descr, E1000_RING_DESC_LEN); - e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len); + e1000e_macreg_write(d, E1000_TDT, (tail + 1) % len); /* Read WB data for the packet transmitted */ qtest_memread(d_pci->pci_dev.bus->qts, @@ -68,13 +68,13 @@ void e1000e_tx_ring_push(QE1000E *d, void *descr) void e1000e_rx_ring_push(QE1000E *d, void *descr) { QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - uint32_t tail = e1000e_macreg_read(d, E1000E_RDT); - uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000_RING_DESC_LEN; + uint32_t tail = e1000e_macreg_read(d, E1000_RDT); + uint32_t len = e1000e_macreg_read(d, E1000_RDLEN) / E1000_RING_DESC_LEN; qtest_memwrite(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000_RING_DESC_LEN, descr, E1000_RING_DESC_LEN); - e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len); + e1000e_macreg_write(d, E1000_RDT, (tail + 1) % len); /* Read WB data for the packet received */ qtest_memread(d_pci->pci_dev.bus->qts, @@ -145,8 +145,8 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj) (uint32_t) d->e1000e.tx_ring); e1000e_macreg_write(&d->e1000e, E1000_TDBAH, (uint32_t) (d->e1000e.tx_ring >> 32)); - e1000e_macreg_write(&d->e1000e, E1000E_TDLEN, E1000E_RING_LEN); - e1000e_macreg_write(&d->e1000e, E1000E_TDT, 0); + e1000e_macreg_write(&d->e1000e, E1000_TDLEN, E1000E_RING_LEN); + e1000e_macreg_write(&d->e1000e, E1000_TDT, 0); e1000e_macreg_write(&d->e1000e, E1000_TDH, 0); /* Enable transmit */ @@ -156,8 +156,8 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj) (uint32_t)d->e1000e.rx_ring); e1000e_macreg_write(&d->e1000e, E1000_RDBAH, (uint32_t)(d->e1000e.rx_ring >> 32)); - e1000e_macreg_write(&d->e1000e, E1000E_RDLEN, E1000E_RING_LEN); - e1000e_macreg_write(&d->e1000e, E1000E_RDT, 0); + e1000e_macreg_write(&d->e1000e, E1000_RDLEN, E1000E_RING_LEN); + e1000e_macreg_write(&d->e1000e, E1000_RDT, 0); e1000e_macreg_write(&d->e1000e, E1000_RDH, 0); /* Enable receive */ diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h index 3bf285af42..091ce139da 100644 --- a/tests/qtest/libqos/e1000e.h +++ b/tests/qtest/libqos/e1000e.h @@ -25,11 +25,6 @@ #define E1000E_RX0_MSG_ID (0) #define E1000E_TX0_MSG_ID (1) -#define E1000E_TDLEN (0x3808) -#define E1000E_TDT (0x3818) -#define E1000E_RDLEN (0x2808) -#define E1000E_RDT (0x2818) - typedef struct QE1000E QE1000E; typedef struct QE1000E_PCI QE1000E_PCI; From 66ef41d29e8a49187b294c2dd3ce083edb2ce606 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 16 Jan 2023 09:30:14 +0100 Subject: [PATCH 103/814] tests/vm/haiku.x86_64: Update the Haiku VM to Beta 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old Haiku VM based on Beta 3 does not work anymore since it fails to install the additional packages now that Beta 4 has been released. Thanks to Alexander von Gluck IV for providing a new image based on Beta 4, we can now upgrade the test image in our QEMU CI, too, to get this working again. Note that Haiku Beta 4 apparently finally fixed the issue with the enumeration of the virtio-block devices (see the ticket at https://dev.haiku-os.org/ticket/16512 ) - the tarball disk can now be found at index 1 instead of index 0. Message-Id: <20230116083014.55647-1-thuth@redhat.com> Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/vm/haiku.x86_64 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/vm/haiku.x86_64 b/tests/vm/haiku.x86_64 index 29668bc272..71cf75a9a3 100755 --- a/tests/vm/haiku.x86_64 +++ b/tests/vm/haiku.x86_64 @@ -48,8 +48,8 @@ class HaikuVM(basevm.BaseVM): name = "haiku" arch = "x86_64" - link = "https://app.vagrantup.com/haiku-os/boxes/r1beta3-x86_64/versions/20220216/providers/libvirt.box" - csum = "e67d4aacbcc687013d5cc91990ddd86cc5d70a5d28432ae2691944f8ce5d5041" + link = "https://app.vagrantup.com/haiku-os/boxes/r1beta4-x86_64/versions/20230114/providers/libvirt.box" + csum = "6e72a2a470e03dbc3c5e808664e057bb4022b390dca88e4c7da6188f26f6a3c9" poweroff = "shutdown" @@ -80,13 +80,12 @@ class HaikuVM(basevm.BaseVM): "ninja", ] - # https://dev.haiku-os.org/ticket/16512 virtio disk1 shows up as 0 (reversed order) BUILD_SCRIPT = """ set -e; rm -rf /tmp/qemu-test.* cd $(mktemp -d /tmp/qemu-test.XXXXXX); mkdir src build; cd src; - tar -xf /dev/disk/virtual/virtio_block/0/raw; + tar -xf /dev/disk/virtual/virtio_block/1/raw; mkdir -p /usr/bin ln -s /boot/system/bin/env /usr/bin/env cd ../build From 75d7150c636569f6687f7e70a33be893be43eb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 16 Jan 2023 18:46:05 +0100 Subject: [PATCH 104/814] s390x/pv: Implement a CGS check helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a protected VM is started with the maximum number of CPUs (248), the service call providing information on the CPUs requires more buffer space than allocated and QEMU disgracefully aborts : LOADPARM=[........] Using virtio-blk. Using SCSI scheme. ................................................................................... qemu-system-s390x: KVM_S390_MEM_OP failed: Argument list too long When protected virtualization is initialized, compute the maximum number of vCPUs supported by the machine and return useful information to the user before the machine starts in case of error. Suggested-by: Thomas Huth Reviewed-by: Thomas Huth Signed-off-by: Cédric Le Goater Message-Id: <20230116174607.2459498-2-clg@kaod.org> Signed-off-by: Thomas Huth --- hw/s390x/pv.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index 8dfe92d8df..8a1c71436b 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -20,6 +20,7 @@ #include "exec/confidential-guest-support.h" #include "hw/s390x/ipl.h" #include "hw/s390x/pv.h" +#include "hw/s390x/sclp.h" #include "target/s390x/kvm/kvm_s390x.h" static bool info_valid; @@ -249,6 +250,41 @@ struct S390PVGuestClass { ConfidentialGuestSupportClass parent_class; }; +/* + * If protected virtualization is enabled, the amount of data that the + * Read SCP Info Service Call can use is limited to one page. The + * available space also depends on the Extended-Length SCCB (ELS) + * feature which can take more buffer space to store feature + * information. This impacts the maximum number of CPUs supported in + * the machine. + */ +static uint32_t s390_pv_get_max_cpus(void) +{ + int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ? + offsetof(ReadInfo, entries) : SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET; + + return (TARGET_PAGE_SIZE - offset_cpu) / sizeof(CPUEntry); +} + +static bool s390_pv_check_cpus(Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + uint32_t pv_max_cpus = s390_pv_get_max_cpus(); + + if (ms->smp.max_cpus > pv_max_cpus) { + error_setg(errp, "Protected VMs support a maximum of %d CPUs", + pv_max_cpus); + return false; + } + + return true; +} + +static bool s390_pv_guest_check(ConfidentialGuestSupport *cgs, Error **errp) +{ + return s390_pv_check_cpus(errp); +} + int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) { @@ -261,6 +297,10 @@ int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) return -1; } + if (!s390_pv_guest_check(cgs, errp)) { + return -1; + } + cgs->ready = true; return 0; From 23792478103f444e34621de0ac3b19ef648ae752 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:14:31 +0100 Subject: [PATCH 105/814] coroutine: Clean up superfluous inclusion of qemu/coroutine.h Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-Id: <20221221131435.3851212-2-armbru@redhat.com> --- blockjob.c | 1 - crypto/block-luks-priv.h | 1 - crypto/block-luks.c | 1 - hw/9pfs/codir.c | 1 - hw/9pfs/cofile.c | 1 - hw/9pfs/cofs.c | 1 - hw/9pfs/coxattr.c | 1 - include/block/raw-aio.h | 1 - include/scsi/pr-manager.h | 1 - nbd/nbd-internal.h | 1 - tests/unit/test-coroutine.c | 1 - tests/unit/test-vmstate.c | 1 - util/qemu-coroutine-lock.c | 1 - util/qemu-coroutine-sleep.c | 1 - util/qemu-coroutine.c | 1 - 15 files changed, 15 deletions(-) diff --git a/blockjob.c b/blockjob.c index b7daf2a9f6..54b4091a36 100644 --- a/blockjob.c +++ b/blockjob.c @@ -32,7 +32,6 @@ #include "qapi/error.h" #include "qapi/qapi-events-block-core.h" #include "qapi/qmp/qerror.h" -#include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "qemu/timer.h" diff --git a/crypto/block-luks-priv.h b/crypto/block-luks-priv.h index 90a20d432b..dc2dd14e52 100644 --- a/crypto/block-luks-priv.h +++ b/crypto/block-luks-priv.h @@ -31,7 +31,6 @@ #include "crypto/random.h" #include "qemu/uuid.h" -#include "qemu/coroutine.h" #include "qemu/bitmap.h" /* diff --git a/crypto/block-luks.c b/crypto/block-luks.c index ff9e3945d1..5688783ab1 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -32,7 +32,6 @@ #include "crypto/random.h" #include "qemu/uuid.h" -#include "qemu/coroutine.h" #include "qemu/bitmap.h" /* diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 93ba44fb75..7ba63be489 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "coth.h" #include "9p-xattr.h" diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 20f93a90e7..9c5344039e 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "coth.h" diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 9d0adc2e78..67e3ae5c5c 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "coth.h" diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index dbcd09e0fd..cd0f8488ac 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" -#include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "coth.h" diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h index 21fc10c4c9..f8cda9df91 100644 --- a/include/block/raw-aio.h +++ b/include/block/raw-aio.h @@ -17,7 +17,6 @@ #define QEMU_RAW_AIO_H #include "block/aio.h" -#include "qemu/coroutine.h" #include "qemu/iov.h" /* AIO request types */ diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h index e4ecbe00f6..45de28d354 100644 --- a/include/scsi/pr-manager.h +++ b/include/scsi/pr-manager.h @@ -5,7 +5,6 @@ #include "qapi/visitor.h" #include "qom/object_interfaces.h" #include "block/aio.h" -#include "qemu/coroutine.h" #define TYPE_PR_MANAGER "pr-manager" diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 1b2141ab4b..df42fef706 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -13,7 +13,6 @@ #include "sysemu/block-backend.h" #include "io/channel-tls.h" -#include "qemu/coroutine.h" #include "qemu/iov.h" #ifndef _WIN32 diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index e16b80c245..513800d3db 100644 --- a/tests/unit/test-coroutine.c +++ b/tests/unit/test-coroutine.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu/coroutine.h" #include "qemu/coroutine_int.h" #include "qemu/lockable.h" diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c index 541bb4f63e..79357b29ca 100644 --- a/tests/unit/test-vmstate.c +++ b/tests/unit/test-vmstate.c @@ -29,7 +29,6 @@ #include "migration/qemu-file-types.h" #include "../migration/qemu-file.h" #include "../migration/savevm.h" -#include "qemu/coroutine.h" #include "qemu/module.h" #include "io/channel-file.h" diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 45c6b57374..58f3f77181 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -27,7 +27,6 @@ */ #include "qemu/osdep.h" -#include "qemu/coroutine.h" #include "qemu/coroutine_int.h" #include "qemu/processor.h" #include "qemu/queue.h" diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 571ab521ff..af59f9af98 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu/coroutine.h" #include "qemu/coroutine_int.h" #include "qemu/timer.h" #include "block/aio.h" diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 356b746f0b..8494523692 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -16,7 +16,6 @@ #include "trace.h" #include "qemu/thread.h" #include "qemu/atomic.h" -#include "qemu/coroutine.h" #include "qemu/coroutine_int.h" #include "qemu/coroutine-tls.h" #include "block/aio.h" From af7f8eb591b45e9a950f2622b96640ff1f2a6794 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:14:32 +0100 Subject: [PATCH 106/814] coroutine: Move coroutine_fn to qemu/osdep.h, trim includes block/block-hmp-cmds.h and qemu/co-shared-resource.h use coroutine_fn without including qemu/coroutine.h. They compile only if it's already included from elsewhere. I could fix that, but pulling in qemu/coroutine.h and everything it includes just for a macro that expands into nothing feels silly. Instead, move the macro to qemu/osdep.h. Inclusions of qemu/coroutine.h just for coroutine_fn become superfluous. Drop them. Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-Id: <20221221131435.3851212-3-armbru@redhat.com> --- include/block/aio_task.h | 2 -- include/block/block-common.h | 1 - include/block/graph-lock.h | 2 -- include/monitor/hmp.h | 1 - include/qemu/coroutine.h | 18 +++++++----------- include/qemu/osdep.h | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/include/block/aio_task.h b/include/block/aio_task.h index 50bc1e1817..18a9c41f4e 100644 --- a/include/block/aio_task.h +++ b/include/block/aio_task.h @@ -25,8 +25,6 @@ #ifndef BLOCK_AIO_TASK_H #define BLOCK_AIO_TASK_H -#include "qemu/coroutine.h" - typedef struct AioTaskPool AioTaskPool; typedef struct AioTask AioTask; typedef int coroutine_fn (*AioTaskFunc)(AioTask *task); diff --git a/include/block/block-common.h b/include/block/block-common.h index 4749c46a5e..434ffc5d34 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -27,7 +27,6 @@ #include "block/aio.h" #include "block/aio-wait.h" #include "qemu/iov.h" -#include "qemu/coroutine.h" #include "block/accounting.h" #include "qemu/hbitmap.h" #include "qemu/transactions.h" diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h index 4c92cd8edf..3ab924d5e2 100644 --- a/include/block/graph-lock.h +++ b/include/block/graph-lock.h @@ -23,8 +23,6 @@ #include "qemu/osdep.h" #include "qemu/clang-tsa.h" -#include "qemu/coroutine.h" - /** * Graph Lock API * This API provides a rwlock used to protect block layer diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 27f86399f7..c9e3887737 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -15,7 +15,6 @@ #define HMP_H #include "qemu/readline.h" -#include "qemu/coroutine.h" #include "qapi/qapi-types-common.h" bool hmp_handle_error(Monitor *mon, Error *err); diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 89650a2d7f..2496a4f4ef 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -26,23 +26,19 @@ * waiting for events to complete. * * These functions are re-entrant and may be used outside the global mutex. - */ - -/** - * Mark a function that executes in coroutine context * - * Functions that execute in coroutine context cannot be called directly from - * normal functions. In the future it would be nice to enable compiler or - * static checker support for catching such errors. This annotation might make - * it possible and in the meantime it serves as documentation. - * - * For example: + * Functions that execute in coroutine context cannot be called + * directly from normal functions. Use @coroutine_fn to mark such + * functions. For example: * * static void coroutine_fn foo(void) { * .... * } + * + * In the future it would be nice to have the compiler or a static + * checker catch misuse of such functions. This annotation might make + * it possible and in the meantime it serves as documentation. */ -#define coroutine_fn typedef struct Coroutine Coroutine; diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index bd23a08595..c850001408 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -157,6 +157,22 @@ extern "C" { #include "qemu/typedefs.h" +/** + * Mark a function that executes in coroutine context + * + * Functions that execute in coroutine context cannot be called directly from + * normal functions. In the future it would be nice to enable compiler or + * static checker support for catching such errors. This annotation might make + * it possible and in the meantime it serves as documentation. + * + * For example: + * + * static void coroutine_fn foo(void) { + * .... + * } + */ +#define coroutine_fn + /* * For mingw, as of v6.0.0, the function implementing the assert macro is * not marked as noreturn, so the compiler cannot delete code following an From df4bbc9dcb09d9e3a385ca1a2a23daad0819f531 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:14:33 +0100 Subject: [PATCH 107/814] coroutine: Clean up superfluous inclusion of qemu/lockable.h Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-Id: <20221221131435.3851212-4-armbru@redhat.com> --- block/progress_meter.c | 2 ++ include/qemu/progress_meter.h | 2 +- tests/unit/test-coroutine.c | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/block/progress_meter.c b/block/progress_meter.c index aa2e60248c..31a170a2cd 100644 --- a/block/progress_meter.c +++ b/block/progress_meter.c @@ -23,7 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "qemu/osdep.h" +#include "qemu/coroutine.h" #include "qemu/progress_meter.h" void progress_init(ProgressMeter *pm) diff --git a/include/qemu/progress_meter.h b/include/qemu/progress_meter.h index dadf822bbf..0f2c0a32d2 100644 --- a/include/qemu/progress_meter.h +++ b/include/qemu/progress_meter.h @@ -27,7 +27,7 @@ #ifndef QEMU_PROGRESS_METER_H #define QEMU_PROGRESS_METER_H -#include "qemu/lockable.h" +#include "qemu/thread.h" typedef struct ProgressMeter { /** diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index 513800d3db..b0d21d673a 100644 --- a/tests/unit/test-coroutine.c +++ b/tests/unit/test-coroutine.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qemu/coroutine_int.h" -#include "qemu/lockable.h" /* * Check that qemu_in_coroutine() works From 49e56287cccfe8b5def4bc4916f367b9a0303161 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:05 +0100 Subject: [PATCH 108/814] ui: Check numeric part of expire_password argument @time properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When argument @time isn't 'now' or 'never', we parse it as an integer, optionally prefixed with '+'. If parsing fails, we silently assume zero. Report an error and fail instead. While there, use qemu_strtou64() instead of strtoull() so checkpatch.pl won't complain. Aside: encoding numbers in strings is bad QMP practice. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-2-armbru@redhat.com> --- monitor/qmp-cmds.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 2932b3f3a5..a1695b6c96 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -201,15 +201,28 @@ void qmp_expire_password(ExpirePasswordOptions *opts, Error **errp) time_t when; int rc; const char *whenstr = opts->time; + const char *numstr = NULL; + uint64_t num; if (strcmp(whenstr, "now") == 0) { when = 0; } else if (strcmp(whenstr, "never") == 0) { when = TIME_MAX; } else if (whenstr[0] == '+') { - when = time(NULL) + strtoull(whenstr+1, NULL, 10); + when = time(NULL); + numstr = whenstr + 1; } else { - when = strtoull(whenstr, NULL, 10); + when = 0; + numstr = whenstr; + } + + if (numstr) { + if (qemu_strtou64(numstr, NULL, 10, &num) < 0) { + error_setg(errp, "Parameter 'time' doesn't take value '%s'", + whenstr); + return; + } + when += num; } if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { From 147c48791be34f3d28faa00b625780c881095be9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:06 +0100 Subject: [PATCH 109/814] ui: Fix silent truncation of numeric keys in HMP sendkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keys are int. HMP sendkey assigns them from the value strtoul(), silently truncating values greater than INT_MAX. Fix to reject them. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-3-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- monitor/hmp-cmds.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index ed78a87ddd..9947ff0b45 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1549,8 +1549,12 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict) v = g_malloc0(sizeof(*v)); if (strstart(keys, "0x", NULL)) { - char *endp; - int value = strtoul(keys, &endp, 0); + const char *endp; + int value; + + if (qemu_strtoi(keys, &endp, 0, &value) < 0) { + goto err_out; + } assert(endp <= keys + keyname_len); if (endp != keys + keyname_len) { goto err_out; From 5c167b5301fc95731134886dfa61ce8c2de9f8c3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:07 +0100 Subject: [PATCH 110/814] ui/spice: Require spice-protocol >= 0.14.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version 0.14.0 is now old enough to have made it into the major distributions: Debian 11: 0.14.3 RHEL-8: 0.14.2 FreeBSD (ports): 0.14.4 Fedora 35: 0.14.0 Ubuntu 20.04: 0.14.0 OpenSUSE Leap 15.3: 0.14.3 Requiring it lets us drop two version checks in ui/vdagent.c. It also enables the next commit. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-4-armbru@redhat.com> --- meson.build | 2 +- ui/vdagent.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 58d8cd68a6..c678460cf6 100644 --- a/meson.build +++ b/meson.build @@ -742,7 +742,7 @@ endif spice_protocol = not_found if not get_option('spice_protocol').auto() or have_system - spice_protocol = dependency('spice-protocol', version: '>=0.12.3', + spice_protocol = dependency('spice-protocol', version: '>=0.14.0', required: get_option('spice_protocol'), method: 'pkg-config', kwargs: static_kwargs) endif diff --git a/ui/vdagent.c b/ui/vdagent.c index 4bf50f0c4d..1f51a78da1 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -87,9 +87,7 @@ static const char *cap_name[] = { [VD_AGENT_CAP_MONITORS_CONFIG_POSITION] = "monitors-config-position", [VD_AGENT_CAP_FILE_XFER_DISABLED] = "file-xfer-disabled", [VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS] = "file-xfer-detailed-errors", -#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 0) [VD_AGENT_CAP_GRAPHICS_DEVICE_INFO] = "graphics-device-info", -#endif #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1) [VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB] = "clipboard-no-release-on-regrab", [VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL] = "clipboard-grab-serial", @@ -112,9 +110,7 @@ static const char *msg_name[] = { [VD_AGENT_CLIENT_DISCONNECTED] = "client-disconnected", [VD_AGENT_MAX_CLIPBOARD] = "max-clipboard", [VD_AGENT_AUDIO_VOLUME_SYNC] = "audio-volume-sync", -#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 0) [VD_AGENT_GRAPHICS_DEVICE_INFO] = "graphics-device-info", -#endif }; static const char *sel_name[] = { From f4c1bcb8c447cde358c9560672d13b90018074e8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:08 +0100 Subject: [PATCH 111/814] Revert "hmp: info spice: take out webdav" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7c6044a94e52db8aef9a71d616c7a0914adb71ab. We had to take it out because SPICE_CHANNEL_WEBDAV requires spice-protocol 0.12.7, but we had only 0.12.3. We have 0.14.0 now, so put it back in. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-5-armbru@redhat.com> --- monitor/hmp-cmds.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 9947ff0b45..67e39f408e 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -622,12 +622,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict) [SPICE_CHANNEL_SMARTCARD] = "smartcard", [SPICE_CHANNEL_USBREDIR] = "usbredir", [SPICE_CHANNEL_PORT] = "port", -#if 0 - /* minimum spice-protocol is 0.12.3, webdav was added in 0.12.7, - * no easy way to #ifdef (SPICE_CHANNEL_* is a enum). Disable - * as quick fix for build failures with older versions. */ [SPICE_CHANNEL_WEBDAV] = "webdav", -#endif }; info = qmp_query_spice(NULL); From 34d55725e664445ccd5621165b1ef805197a530e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:09 +0100 Subject: [PATCH 112/814] ui/spice: Require spice-server >= 0.14.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version 0.14.0 is now old enough to have made it into the major distributions: Debian 11: 0.14.3 RHEL-8: 0.14.3 FreeBSD (ports): 0.15.0 Fedora 35: 0.15.0 Ubuntu 20.04: 0.14.2 OpenSUSE Leap 15.3: 0.14.3 Requiring it lets us drop a number of version checks. The next commit will clean up some more. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-6-armbru@redhat.com> --- chardev/spice.c | 2 -- hw/display/qxl.c | 7 +------ hw/display/qxl.h | 2 -- include/ui/qemu-spice.h | 6 +----- include/ui/spice-display.h | 2 -- meson.build | 2 +- 6 files changed, 3 insertions(+), 18 deletions(-) diff --git a/chardev/spice.c b/chardev/spice.c index bbffef4913..e843d961a7 100644 --- a/chardev/spice.c +++ b/chardev/spice.c @@ -98,9 +98,7 @@ static SpiceCharDeviceInterface vmc_interface = { .write = vmc_write, .read = vmc_read, .event = vmc_event, -#if SPICE_SERVER_VERSION >= 0x000c06 .flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE, -#endif }; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 6772849dec..ddca611804 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -260,8 +260,7 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, 0)); } else { -/* >= release 0.12.6, < release 0.14.2 */ -#if SPICE_SERVER_VERSION >= 0x000c06 && SPICE_SERVER_VERSION < 0x000e02 +#if SPICE_SERVER_VERSION < 0x000e02 /* release 0.14.2 */ if (qxl->max_outputs) { spice_qxl_set_max_monitors(&qxl->ssd.qxl, qxl->max_outputs); } @@ -1089,12 +1088,10 @@ static int interface_client_monitors_config(QXLInstance *sin, return 1; } -#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ /* limit number of outputs based on setting limit */ if (qxl->max_outputs && qxl->max_outputs <= max_outputs) { max_outputs = qxl->max_outputs; } -#endif config_changed = qxl_rom_monitors_config_changed(rom, monitors_config, @@ -2487,9 +2484,7 @@ static Property qxl_properties[] = { DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), -#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0), -#endif DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0), DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0), DEFINE_PROP_BOOL("global-vmstate", PCIQXLDevice, vga.global_vmstate, false), diff --git a/hw/display/qxl.h b/hw/display/qxl.h index cd82c7a6fe..fdac14edad 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -99,9 +99,7 @@ struct PCIQXLDevice { QXLModes *modes; uint32_t rom_size; MemoryRegion rom_bar; -#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ uint16_t max_outputs; -#endif /* vram pci bar */ uint64_t vram_size; diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index 21fe195e18..a7a1890b3f 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -34,13 +34,9 @@ int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con); int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, const char *subject); -#if !defined(SPICE_SERVER_VERSION) || (SPICE_SERVER_VERSION < 0xc06) -#define SPICE_NEEDS_SET_MM_TIME 1 -#else #define SPICE_NEEDS_SET_MM_TIME 0 -#endif -#if defined(SPICE_SERVER_VERSION) && (SPICE_SERVER_VERSION >= 0x000f00) +#if SPICE_SERVER_VERSION >= 0x000f00 /* release 0.15.0 */ #define SPICE_HAS_ATTACHED_WORKER 1 #else #define SPICE_HAS_ATTACHED_WORKER 0 diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index e271e011da..5aa13664d6 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -28,11 +28,9 @@ #include "ui/console.h" #if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) -# if SPICE_SERVER_VERSION >= 0x000d01 /* release 0.13.1 */ # define HAVE_SPICE_GL 1 # include "ui/egl-helpers.h" # include "ui/egl-context.h" -# endif #endif #define NUM_MEMSLOTS 8 diff --git a/meson.build b/meson.build index c678460cf6..6d3b665629 100644 --- a/meson.build +++ b/meson.build @@ -748,7 +748,7 @@ if not get_option('spice_protocol').auto() or have_system endif spice = not_found if not get_option('spice').auto() or have_system - spice = dependency('spice-server', version: '>=0.12.5', + spice = dependency('spice-server', version: '>=0.14.0', required: get_option('spice'), method: 'pkg-config', kwargs: static_kwargs) endif From dfa258481649edc383c444b3e3eb578a5bf93aa6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:10 +0100 Subject: [PATCH 113/814] ui/spice: QXLInterface method set_mm_time() is now dead, drop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPICE_NEEDS_SET_MM_TIME is now always off. Bury the dead code. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20230109190321.1056914-7-armbru@redhat.com> --- hw/display/qxl.c | 19 ------------------- hw/display/trace-events | 1 - include/ui/qemu-spice.h | 2 -- ui/spice-display.c | 10 ---------- 4 files changed, 32 deletions(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index ddca611804..ec712d3ca2 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -543,22 +543,6 @@ static void interface_set_compression_level(QXLInstance *sin, int level) qxl_rom_set_dirty(qxl); } -#if SPICE_NEEDS_SET_MM_TIME -static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) -{ - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - - if (!qemu_spice_display_is_running(&qxl->ssd)) { - return; - } - - trace_qxl_interface_set_mm_time(qxl->id, mm_time); - qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); - qxl->rom->mm_clock = cpu_to_le32(mm_time); - qxl_rom_set_dirty(qxl); -} -#endif - static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); @@ -1145,9 +1129,6 @@ static const QXLInterface qxl_interface = { #endif .set_compression_level = interface_set_compression_level, -#if SPICE_NEEDS_SET_MM_TIME - .set_mm_time = interface_set_mm_time, -#endif .get_init_info = interface_get_init_info, /* the callbacks below are called from spice server thread context */ diff --git a/hw/display/trace-events b/hw/display/trace-events index 0c0ffcbe42..2336a0ca15 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -55,7 +55,6 @@ virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 # qxl.c -disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %ux%u mem=0x%" PRIx64 " %u,%u" qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d" diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index a7a1890b3f..b7d493742c 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -34,8 +34,6 @@ int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con); int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, const char *subject); -#define SPICE_NEEDS_SET_MM_TIME 0 - #if SPICE_SERVER_VERSION >= 0x000f00 /* release 0.15.0 */ #define SPICE_HAS_ATTACHED_WORKER 1 #else diff --git a/ui/spice-display.c b/ui/spice-display.c index 494168e7fe..0616a6982f 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -517,13 +517,6 @@ static void interface_set_compression_level(QXLInstance *sin, int level) /* nothing to do */ } -#if SPICE_NEEDS_SET_MM_TIME -static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) -{ - /* nothing to do */ -} -#endif - static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); @@ -715,9 +708,6 @@ static const QXLInterface dpy_interface = { .attache_worker = interface_attach_worker, #endif .set_compression_level = interface_set_compression_level, -#if SPICE_NEEDS_SET_MM_TIME - .set_mm_time = interface_set_mm_time, -#endif .get_init_info = interface_get_init_info, /* the callbacks below are called from spice server thread context */ From 10e3c47a5d62dc746375f55b7b7313f0343dab1d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:11 +0100 Subject: [PATCH 114/814] ui/spice: Give hmp_info_spice()'s channel_names[] static linkage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-8-armbru@redhat.com> --- monitor/hmp-cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 67e39f408e..f4d0d031df 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -611,7 +611,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict) SpiceChannelList *chan; SpiceInfo *info; const char *channel_name; - const char * const channel_names[] = { + static const char *const channel_names[] = { [SPICE_CHANNEL_MAIN] = "main", [SPICE_CHANNEL_DISPLAY] = "display", [SPICE_CHANNEL_INPUTS] = "inputs", From 61d7f2a9569b56ac1970d52fe3c7683e70998ed8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:12 +0100 Subject: [PATCH 115/814] ui: Clean up a few things checkpatch.pl would flag later on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a few style violations so that checkpatch.pl won't complain when I move this code. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-9-armbru@redhat.com> --- monitor/hmp-cmds.c | 7 ++++--- monitor/qmp-cmds.c | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index f4d0d031df..c2249f77a6 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -587,9 +587,10 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) hmp_info_vnc_servers(mon, info->server); hmp_info_vnc_clients(mon, info->clients); if (!info->server) { - /* The server entry displays its auth, we only - * need to display in the case of 'reverse' connections - * where there's no server. + /* + * The server entry displays its auth, we only need to + * display in the case of 'reverse' connections where + * there's no server. */ hmp_info_vnc_authcrypt(mon, " ", info->auth, info->has_vencrypt ? &info->vencrypt : NULL); diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index a1695b6c96..6d6df86607 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -186,8 +186,10 @@ void qmp_set_password(SetPasswordOptions *opts, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER, "connected"); return; } - /* Note that setting an empty password will not disable login through - * this interface. */ + /* + * Note that setting an empty password will not disable login + * through this interface. + */ rc = vnc_display_password(opts->u.vnc.display, opts->password); } @@ -272,12 +274,10 @@ void qmp_add_client(const char *protocol, const char *fdname, error_setg(errp, "spice failed to add client"); close(fd); } - return; #ifdef CONFIG_VNC } else if (strcmp(protocol, "vnc") == 0) { skipauth = has_skipauth ? skipauth : false; vnc_display_add_client(NULL, fd, skipauth); - return; #endif #ifdef CONFIG_DBUS_DISPLAY } else if (strcmp(protocol, "@dbus-display") == 0) { @@ -289,19 +289,20 @@ void qmp_add_client(const char *protocol, const char *fdname, close(fd); return; } - return; #endif - } else if ((s = qemu_chr_find(protocol)) != NULL) { + } else { + s = qemu_chr_find(protocol); + if (!s) { + error_setg(errp, "protocol '%s' is invalid", protocol); + close(fd); + return; + } if (qemu_chr_add_client(s, fd) < 0) { error_setg(errp, "failed to add client"); close(fd); return; } - return; } - - error_setg(errp, "protocol '%s' is invalid", protocol); - close(fd); } From 9949b06e2e95f821a76215194413bb78aa782d53 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:13 +0100 Subject: [PATCH 116/814] ui: Move QMP commands from monitor to new ui/ui-qmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves these commands from MAINTAINERS section "QMP" to "Graphics". Command add-client applies to socket character devices in addition to display devices. Move it anyway. Aside: the way @protocol character device IDs and display types is bad design. Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-10-armbru@redhat.com> --- monitor/qmp-cmds.c | 118 --------------------------------------- ui/meson.build | 1 + ui/ui-qmp-cmds.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 118 deletions(-) create mode 100644 ui/ui-qmp-cmds.c diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 6d6df86607..61449f1b58 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -36,9 +36,7 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-stats.h" -#include "qapi/qapi-commands-ui.h" #include "qapi/type-helpers.h" -#include "qapi/qmp/qerror.h" #include "exec/ramlist.h" #include "hw/mem/memory-device.h" #include "hw/acpi/acpi_dev_interface.h" @@ -168,89 +166,6 @@ void qmp_system_wakeup(Error **errp) qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); } -void qmp_set_password(SetPasswordOptions *opts, Error **errp) -{ - int rc; - - if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { - if (!qemu_using_spice(errp)) { - return; - } - rc = qemu_spice.set_passwd(opts->password, - opts->connected == SET_PASSWORD_ACTION_FAIL, - opts->connected == SET_PASSWORD_ACTION_DISCONNECT); - } else { - assert(opts->protocol == DISPLAY_PROTOCOL_VNC); - if (opts->connected != SET_PASSWORD_ACTION_KEEP) { - /* vnc supports "connected=keep" only */ - error_setg(errp, QERR_INVALID_PARAMETER, "connected"); - return; - } - /* - * Note that setting an empty password will not disable login - * through this interface. - */ - rc = vnc_display_password(opts->u.vnc.display, opts->password); - } - - if (rc != 0) { - error_setg(errp, "Could not set password"); - } -} - -void qmp_expire_password(ExpirePasswordOptions *opts, Error **errp) -{ - time_t when; - int rc; - const char *whenstr = opts->time; - const char *numstr = NULL; - uint64_t num; - - if (strcmp(whenstr, "now") == 0) { - when = 0; - } else if (strcmp(whenstr, "never") == 0) { - when = TIME_MAX; - } else if (whenstr[0] == '+') { - when = time(NULL); - numstr = whenstr + 1; - } else { - when = 0; - numstr = whenstr; - } - - if (numstr) { - if (qemu_strtou64(numstr, NULL, 10, &num) < 0) { - error_setg(errp, "Parameter 'time' doesn't take value '%s'", - whenstr); - return; - } - when += num; - } - - if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { - if (!qemu_using_spice(errp)) { - return; - } - rc = qemu_spice.set_pw_expire(when); - } else { - assert(opts->protocol == DISPLAY_PROTOCOL_VNC); - rc = vnc_display_pw_expire(opts->u.vnc.display, when); - } - - if (rc != 0) { - error_setg(errp, "Could not set password expire time"); - } -} - -#ifdef CONFIG_VNC -void qmp_change_vnc_password(const char *password, Error **errp) -{ - if (vnc_display_password(NULL, password) < 0) { - error_setg(errp, "Could not set password"); - } -} -#endif - void qmp_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) @@ -305,7 +220,6 @@ void qmp_add_client(const char *protocol, const char *fdname, } } - MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) { return qmp_memory_device_list(); @@ -344,38 +258,6 @@ MemoryInfo *qmp_query_memory_size_summary(Error **errp) return mem_info; } -void qmp_display_reload(DisplayReloadOptions *arg, Error **errp) -{ - switch (arg->type) { - case DISPLAY_RELOAD_TYPE_VNC: -#ifdef CONFIG_VNC - if (arg->u.vnc.has_tls_certs && arg->u.vnc.tls_certs) { - vnc_display_reload_certs(NULL, errp); - } -#else - error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'"); -#endif - break; - default: - abort(); - } -} - -void qmp_display_update(DisplayUpdateOptions *arg, Error **errp) -{ - switch (arg->type) { - case DISPLAY_UPDATE_TYPE_VNC: -#ifdef CONFIG_VNC - vnc_display_update(&arg->u.vnc, errp); -#else - error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'"); -#endif - break; - default: - abort(); - } -} - static int qmp_x_query_rdma_foreach(Object *obj, void *opaque) { RdmaProvider *rdma; diff --git a/ui/meson.build b/ui/meson.build index c1b137bf33..9194ea335b 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -14,6 +14,7 @@ softmmu_ss.add(files( 'kbd-state.c', 'keymaps.c', 'qemu-pixman.c', + 'ui-qmp-cmds.c', 'util.c', )) if dbus_display diff --git a/ui/ui-qmp-cmds.c b/ui/ui-qmp-cmds.c new file mode 100644 index 0000000000..c9f92caf1d --- /dev/null +++ b/ui/ui-qmp-cmds.c @@ -0,0 +1,136 @@ +/* + * QMP commands related to UI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-commands-ui.h" +#include "qapi/qmp/qerror.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "ui/qemu-spice.h" + +void qmp_set_password(SetPasswordOptions *opts, Error **errp) +{ + int rc; + + if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { + if (!qemu_using_spice(errp)) { + return; + } + rc = qemu_spice.set_passwd(opts->password, + opts->connected == SET_PASSWORD_ACTION_FAIL, + opts->connected == SET_PASSWORD_ACTION_DISCONNECT); + } else { + assert(opts->protocol == DISPLAY_PROTOCOL_VNC); + if (opts->connected != SET_PASSWORD_ACTION_KEEP) { + /* vnc supports "connected=keep" only */ + error_setg(errp, QERR_INVALID_PARAMETER, "connected"); + return; + } + /* + * Note that setting an empty password will not disable login + * through this interface. + */ + rc = vnc_display_password(opts->u.vnc.display, opts->password); + } + + if (rc != 0) { + error_setg(errp, "Could not set password"); + } +} + +void qmp_expire_password(ExpirePasswordOptions *opts, Error **errp) +{ + time_t when; + int rc; + const char *whenstr = opts->time; + const char *numstr = NULL; + uint64_t num; + + if (strcmp(whenstr, "now") == 0) { + when = 0; + } else if (strcmp(whenstr, "never") == 0) { + when = TIME_MAX; + } else if (whenstr[0] == '+') { + when = time(NULL); + numstr = whenstr + 1; + } else { + when = 0; + numstr = whenstr; + } + + if (numstr) { + if (qemu_strtou64(numstr, NULL, 10, &num) < 0) { + error_setg(errp, "Parameter 'time' doesn't take value '%s'", + whenstr); + return; + } + when += num; + } + + if (opts->protocol == DISPLAY_PROTOCOL_SPICE) { + if (!qemu_using_spice(errp)) { + return; + } + rc = qemu_spice.set_pw_expire(when); + } else { + assert(opts->protocol == DISPLAY_PROTOCOL_VNC); + rc = vnc_display_pw_expire(opts->u.vnc.display, when); + } + + if (rc != 0) { + error_setg(errp, "Could not set password expire time"); + } +} + +#ifdef CONFIG_VNC +void qmp_change_vnc_password(const char *password, Error **errp) +{ + if (vnc_display_password(NULL, password) < 0) { + error_setg(errp, "Could not set password"); + } +} +#endif + +void qmp_display_reload(DisplayReloadOptions *arg, Error **errp) +{ + switch (arg->type) { + case DISPLAY_RELOAD_TYPE_VNC: +#ifdef CONFIG_VNC + if (arg->u.vnc.has_tls_certs && arg->u.vnc.tls_certs) { + vnc_display_reload_certs(NULL, errp); + } +#else + error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'"); +#endif + break; + default: + abort(); + } +} + +void qmp_display_update(DisplayUpdateOptions *arg, Error **errp) +{ + switch (arg->type) { + case DISPLAY_UPDATE_TYPE_VNC: +#ifdef CONFIG_VNC + vnc_display_update(&arg->u.vnc, errp); +#else + error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'"); +#endif + break; + default: + abort(); + } +} From 3125af295e92825834031e8cbb8ca55c718a6fcb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:14 +0100 Subject: [PATCH 117/814] ui: Factor out qmp_add_client() parts and move to ui/ui-qmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-11-armbru@redhat.com> --- include/monitor/qmp-helpers.h | 26 ++++++++++++ monitor/qmp-cmds.c | 74 ++++++++++++++++------------------- ui/ui-qmp-cmds.c | 41 +++++++++++++++++++ 3 files changed, 100 insertions(+), 41 deletions(-) create mode 100644 include/monitor/qmp-helpers.h diff --git a/include/monitor/qmp-helpers.h b/include/monitor/qmp-helpers.h new file mode 100644 index 0000000000..4718c63c73 --- /dev/null +++ b/include/monitor/qmp-helpers.h @@ -0,0 +1,26 @@ +/* + * QMP command helpers + * + * Copyright (c) 2022 Red Hat Inc. + * + * Authors: + * Markus Armbruster + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef MONITOR_QMP_HELPERS_H + +bool qmp_add_client_spice(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp); +#ifdef CONFIG_VNC +bool qmp_add_client_vnc(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp); +#endif +#ifdef CONFIG_DBUS_DISPLAY +bool qmp_add_client_dbus_display(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp); +#endif + +#endif diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 61449f1b58..b5b736761a 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -17,13 +17,11 @@ #include "qemu/cutils.h" #include "qemu/option.h" #include "monitor/monitor.h" +#include "monitor/qmp-helpers.h" #include "sysemu/sysemu.h" #include "qemu/config-file.h" #include "qemu/uuid.h" #include "chardev/char.h" -#include "ui/qemu-spice.h" -#include "ui/console.h" -#include "ui/dbus-display.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "sysemu/runstate-action.h" @@ -170,54 +168,48 @@ void qmp_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) { + static struct { + const char *name; + bool (*add_client)(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp); + } protocol_table[] = { + { "spice", qmp_add_client_spice }, +#ifdef CONFIG_VNC + { "vnc", qmp_add_client_vnc }, +#endif +#ifdef CONFIG_DBUS_DISPLAY + { "@dbus-display", qmp_add_client_dbus_display }, +#endif + }; Chardev *s; - int fd; + int fd, i; fd = monitor_get_fd(monitor_cur(), fdname, errp); if (fd < 0) { return; } - if (strcmp(protocol, "spice") == 0) { - if (!qemu_using_spice(errp)) { - close(fd); - return; - } - skipauth = has_skipauth ? skipauth : false; - tls = has_tls ? tls : false; - if (qemu_spice.display_add_client(fd, skipauth, tls) < 0) { - error_setg(errp, "spice failed to add client"); - close(fd); - } -#ifdef CONFIG_VNC - } else if (strcmp(protocol, "vnc") == 0) { - skipauth = has_skipauth ? skipauth : false; - vnc_display_add_client(NULL, fd, skipauth); -#endif -#ifdef CONFIG_DBUS_DISPLAY - } else if (strcmp(protocol, "@dbus-display") == 0) { - if (!qemu_using_dbus_display(errp)) { - close(fd); - return; - } - if (!qemu_dbus_display.add_client(fd, errp)) { - close(fd); - return; - } -#endif - } else { - s = qemu_chr_find(protocol); - if (!s) { - error_setg(errp, "protocol '%s' is invalid", protocol); - close(fd); - return; - } - if (qemu_chr_add_client(s, fd) < 0) { - error_setg(errp, "failed to add client"); - close(fd); + for (i = 0; i < ARRAY_SIZE(protocol_table); i++) { + if (!strcmp(protocol, protocol_table[i].name)) { + if (!protocol_table[i].add_client(fd, has_skipauth, skipauth, + has_tls, tls, errp)) { + close(fd); + } return; } } + + s = qemu_chr_find(protocol); + if (!s) { + error_setg(errp, "protocol '%s' is invalid", protocol); + close(fd); + return; + } + if (qemu_chr_add_client(s, fd) < 0) { + error_setg(errp, "failed to add client"); + close(fd); + return; + } } MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) diff --git a/ui/ui-qmp-cmds.c b/ui/ui-qmp-cmds.c index c9f92caf1d..dbc4afcd73 100644 --- a/ui/ui-qmp-cmds.c +++ b/ui/ui-qmp-cmds.c @@ -14,10 +14,12 @@ */ #include "qemu/osdep.h" +#include "monitor/qmp-helpers.h" #include "qapi/qapi-commands-ui.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" #include "ui/console.h" +#include "ui/dbus-display.h" #include "ui/qemu-spice.h" void qmp_set_password(SetPasswordOptions *opts, Error **errp) @@ -103,6 +105,45 @@ void qmp_change_vnc_password(const char *password, Error **errp) } #endif +bool qmp_add_client_spice(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp) +{ + if (!qemu_using_spice(errp)) { + return false; + } + skipauth = has_skipauth ? skipauth : false; + tls = has_tls ? tls : false; + if (qemu_spice.display_add_client(fd, skipauth, tls) < 0) { + error_setg(errp, "spice failed to add client"); + return false; + } + return true; +} + +#ifdef CONFIG_VNC +bool qmp_add_client_vnc(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp) +{ + skipauth = has_skipauth ? skipauth : false; + vnc_display_add_client(NULL, fd, skipauth); + return true; +} +#endif + +#ifdef CONFIG_DBUS_DISPLAY +bool qmp_add_client_dbus_display(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, Error **errp) +{ + if (!qemu_using_dbus_display(errp)) { + return false; + } + if (!qemu_dbus_display.add_client(fd, errp)) { + return false; + } + return true; +} +#endif + void qmp_display_reload(DisplayReloadOptions *arg, Error **errp) { switch (arg->type) { From 5011d262f0580ae7d9acf35256697520db2f1720 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:15 +0100 Subject: [PATCH 118/814] ui: Move HMP commands from monitor to new ui/ui-hmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "Graphics". Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-12-armbru@redhat.com> --- include/monitor/hmp.h | 2 + monitor/hmp-cmds.c | 338 --------------------------------- monitor/misc.c | 66 ------- ui/meson.build | 1 + ui/ui-hmp-cmds.c | 422 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 425 insertions(+), 404 deletions(-) create mode 100644 ui/ui-hmp-cmds.c diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 27f86399f7..b228a406f3 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -81,6 +81,8 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); +void hmp_mouse_move(Monitor *mon, const QDict *qdict); +void hmp_mouse_button(Monitor *mon, const QDict *qdict); void hmp_sendkey(Monitor *mon, const QDict *qdict); void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c2249f77a6..c4f161a596 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -51,7 +51,6 @@ #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" #include "qom/object_interfaces.h" -#include "ui/console.h" #include "qemu/cutils.h" #include "qemu/error-report.h" #include "hw/core/cpu.h" @@ -59,10 +58,6 @@ #include "migration/snapshot.h" #include "migration/misc.h" -#ifdef CONFIG_SPICE -#include -#endif - bool hmp_handle_error(Monitor *mon, Error *err) { if (err) { @@ -178,26 +173,6 @@ void hmp_info_chardev(Monitor *mon, const QDict *qdict) qapi_free_ChardevInfoList(char_info); } -void hmp_info_mice(Monitor *mon, const QDict *qdict) -{ - MouseInfoList *mice_list, *mouse; - - mice_list = qmp_query_mice(NULL); - if (!mice_list) { - monitor_printf(mon, "No mouse devices connected\n"); - return; - } - - for (mouse = mice_list; mouse; mouse = mouse->next) { - monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n", - mouse->value->current ? '*' : ' ', - mouse->value->index, mouse->value->name, - mouse->value->absolute ? " (absolute)" : ""); - } - - qapi_free_MouseInfoList(mice_list); -} - void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; @@ -516,168 +491,6 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) qapi_free_MigrationParameters(params); } - -#ifdef CONFIG_VNC -/* Helper for hmp_info_vnc_clients, _servers */ -static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info, - const char *name) -{ - monitor_printf(mon, " %s: %s:%s (%s%s)\n", - name, - info->host, - info->service, - NetworkAddressFamily_str(info->family), - info->websocket ? " (Websocket)" : ""); -} - -/* Helper displaying and auth and crypt info */ -static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent, - VncPrimaryAuth auth, - VncVencryptSubAuth *vencrypt) -{ - monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent, - VncPrimaryAuth_str(auth), - vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none"); -} - -static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client) -{ - while (client) { - VncClientInfo *cinfo = client->value; - - hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client"); - monitor_printf(mon, " x509_dname: %s\n", - cinfo->x509_dname ?: "none"); - monitor_printf(mon, " sasl_username: %s\n", - cinfo->sasl_username ?: "none"); - - client = client->next; - } -} - -static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server) -{ - while (server) { - VncServerInfo2 *sinfo = server->value; - hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server"); - hmp_info_vnc_authcrypt(mon, " ", sinfo->auth, - sinfo->has_vencrypt ? &sinfo->vencrypt : NULL); - server = server->next; - } -} - -void hmp_info_vnc(Monitor *mon, const QDict *qdict) -{ - VncInfo2List *info2l, *info2l_head; - Error *err = NULL; - - info2l = qmp_query_vnc_servers(&err); - info2l_head = info2l; - if (hmp_handle_error(mon, err)) { - return; - } - if (!info2l) { - monitor_printf(mon, "None\n"); - return; - } - - while (info2l) { - VncInfo2 *info = info2l->value; - monitor_printf(mon, "%s:\n", info->id); - hmp_info_vnc_servers(mon, info->server); - hmp_info_vnc_clients(mon, info->clients); - if (!info->server) { - /* - * The server entry displays its auth, we only need to - * display in the case of 'reverse' connections where - * there's no server. - */ - hmp_info_vnc_authcrypt(mon, " ", info->auth, - info->has_vencrypt ? &info->vencrypt : NULL); - } - if (info->display) { - monitor_printf(mon, " Display: %s\n", info->display); - } - info2l = info2l->next; - } - - qapi_free_VncInfo2List(info2l_head); - -} -#endif - -#ifdef CONFIG_SPICE -void hmp_info_spice(Monitor *mon, const QDict *qdict) -{ - SpiceChannelList *chan; - SpiceInfo *info; - const char *channel_name; - static const char *const channel_names[] = { - [SPICE_CHANNEL_MAIN] = "main", - [SPICE_CHANNEL_DISPLAY] = "display", - [SPICE_CHANNEL_INPUTS] = "inputs", - [SPICE_CHANNEL_CURSOR] = "cursor", - [SPICE_CHANNEL_PLAYBACK] = "playback", - [SPICE_CHANNEL_RECORD] = "record", - [SPICE_CHANNEL_TUNNEL] = "tunnel", - [SPICE_CHANNEL_SMARTCARD] = "smartcard", - [SPICE_CHANNEL_USBREDIR] = "usbredir", - [SPICE_CHANNEL_PORT] = "port", - [SPICE_CHANNEL_WEBDAV] = "webdav", - }; - - info = qmp_query_spice(NULL); - - if (!info->enabled) { - monitor_printf(mon, "Server: disabled\n"); - goto out; - } - - monitor_printf(mon, "Server:\n"); - if (info->has_port) { - monitor_printf(mon, " address: %s:%" PRId64 "\n", - info->host, info->port); - } - if (info->has_tls_port) { - monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", - info->host, info->tls_port); - } - monitor_printf(mon, " migrated: %s\n", - info->migrated ? "true" : "false"); - monitor_printf(mon, " auth: %s\n", info->auth); - monitor_printf(mon, " compiled: %s\n", info->compiled_version); - monitor_printf(mon, " mouse-mode: %s\n", - SpiceQueryMouseMode_str(info->mouse_mode)); - - if (!info->has_channels || info->channels == NULL) { - monitor_printf(mon, "Channels: none\n"); - } else { - for (chan = info->channels; chan; chan = chan->next) { - monitor_printf(mon, "Channel:\n"); - monitor_printf(mon, " address: %s:%s%s\n", - chan->value->host, chan->value->port, - chan->value->tls ? " [tls]" : ""); - monitor_printf(mon, " session: %" PRId64 "\n", - chan->value->connection_id); - monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n", - chan->value->channel_type, chan->value->channel_id); - - channel_name = "unknown"; - if (chan->value->channel_type > 0 && - chan->value->channel_type < ARRAY_SIZE(channel_names) && - channel_names[chan->value->channel_type]) { - channel_name = channel_names[chan->value->channel_type]; - } - - monitor_printf(mon, " channel name: %s\n", channel_name); - } - } - -out: - qapi_free_SpiceInfo(info); -} -#endif - void hmp_info_balloon(Monitor *mon, const QDict *qdict) { BalloonInfo *info; @@ -1262,69 +1075,6 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_set_password(Monitor *mon, const QDict *qdict) -{ - const char *protocol = qdict_get_str(qdict, "protocol"); - const char *password = qdict_get_str(qdict, "password"); - const char *display = qdict_get_try_str(qdict, "display"); - const char *connected = qdict_get_try_str(qdict, "connected"); - Error *err = NULL; - - SetPasswordOptions opts = { - .password = (char *)password, - .has_connected = !!connected, - }; - - opts.connected = qapi_enum_parse(&SetPasswordAction_lookup, connected, - SET_PASSWORD_ACTION_KEEP, &err); - if (err) { - goto out; - } - - opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol, - DISPLAY_PROTOCOL_VNC, &err); - if (err) { - goto out; - } - - if (opts.protocol == DISPLAY_PROTOCOL_VNC) { - opts.u.vnc.display = (char *)display; - } - - qmp_set_password(&opts, &err); - -out: - hmp_handle_error(mon, err); -} - -void hmp_expire_password(Monitor *mon, const QDict *qdict) -{ - const char *protocol = qdict_get_str(qdict, "protocol"); - const char *whenstr = qdict_get_str(qdict, "time"); - const char *display = qdict_get_try_str(qdict, "display"); - Error *err = NULL; - - ExpirePasswordOptions opts = { - .time = (char *)whenstr, - }; - - opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol, - DISPLAY_PROTOCOL_VNC, &err); - if (err) { - goto out; - } - - if (opts.protocol == DISPLAY_PROTOCOL_VNC) { - opts.u.vnc.display = (char *)display; - } - - qmp_expire_password(&opts, &err); - -out: - hmp_handle_error(mon, err); -} - - #ifdef CONFIG_VNC static void hmp_change_read_arg(void *opaque, const char *password, void *readline_opaque) @@ -1521,94 +1271,6 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_sendkey(Monitor *mon, const QDict *qdict) -{ - const char *keys = qdict_get_str(qdict, "keys"); - KeyValue *v = NULL; - KeyValueList *head = NULL, **tail = &head; - int has_hold_time = qdict_haskey(qdict, "hold-time"); - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); - Error *err = NULL; - const char *separator; - int keyname_len; - - while (1) { - separator = qemu_strchrnul(keys, '-'); - keyname_len = separator - keys; - - /* Be compatible with old interface, convert user inputted "<" */ - if (keys[0] == '<' && keyname_len == 1) { - keys = "less"; - keyname_len = 4; - } - - v = g_malloc0(sizeof(*v)); - - if (strstart(keys, "0x", NULL)) { - const char *endp; - int value; - - if (qemu_strtoi(keys, &endp, 0, &value) < 0) { - goto err_out; - } - assert(endp <= keys + keyname_len); - if (endp != keys + keyname_len) { - goto err_out; - } - v->type = KEY_VALUE_KIND_NUMBER; - v->u.number.data = value; - } else { - int idx = index_from_key(keys, keyname_len); - if (idx == Q_KEY_CODE__MAX) { - goto err_out; - } - v->type = KEY_VALUE_KIND_QCODE; - v->u.qcode.data = idx; - } - QAPI_LIST_APPEND(tail, v); - v = NULL; - - if (!*separator) { - break; - } - keys = separator + 1; - } - - qmp_send_key(head, has_hold_time, hold_time, &err); - hmp_handle_error(mon, err); - -out: - qapi_free_KeyValue(v); - qapi_free_KeyValueList(head); - return; - -err_out: - monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys); - goto out; -} - -void coroutine_fn -hmp_screendump(Monitor *mon, const QDict *qdict) -{ - const char *filename = qdict_get_str(qdict, "filename"); - const char *id = qdict_get_try_str(qdict, "device"); - int64_t head = qdict_get_try_int(qdict, "head", 0); - const char *input_format = qdict_get_try_str(qdict, "format"); - Error *err = NULL; - ImageFormat format; - - format = qapi_enum_parse(&ImageFormat_lookup, input_format, - IMAGE_FORMAT_PPM, &err); - if (err) { - goto end; - } - - qmp_screendump(filename, id, id != NULL, head, - input_format != NULL, format, &err); -end: - hmp_handle_error(mon, err); -} - void hmp_chardev_add(Monitor *mon, const QDict *qdict) { const char *args = qdict_get_str(qdict, "args"); diff --git a/monitor/misc.c b/monitor/misc.c index bf3f1c67ca..3d68940d28 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -34,7 +34,6 @@ #include "qemu/config-file.h" #include "qemu/ctype.h" #include "ui/console.h" -#include "ui/input.h" #include "audio/audio.h" #include "disas/disas.h" #include "qemu/timer.h" @@ -825,49 +824,6 @@ static void hmp_sum(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%05d\n", sum); } -static int mouse_button_state; - -static void hmp_mouse_move(Monitor *mon, const QDict *qdict) -{ - int dx, dy, dz, button; - const char *dx_str = qdict_get_str(qdict, "dx_str"); - const char *dy_str = qdict_get_str(qdict, "dy_str"); - const char *dz_str = qdict_get_try_str(qdict, "dz_str"); - - dx = strtol(dx_str, NULL, 0); - dy = strtol(dy_str, NULL, 0); - qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); - qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); - - if (dz_str) { - dz = strtol(dz_str, NULL, 0); - if (dz != 0) { - button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; - qemu_input_queue_btn(NULL, button, true); - qemu_input_event_sync(); - qemu_input_queue_btn(NULL, button, false); - } - } - qemu_input_event_sync(); -} - -static void hmp_mouse_button(Monitor *mon, const QDict *qdict) -{ - static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, - [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, - [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, - }; - int button_state = qdict_get_int(qdict, "button_state"); - - if (mouse_button_state == button_state) { - return; - } - qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state); - qemu_input_event_sync(); - mouse_button_state = button_state; -} - static void hmp_ioport_read(Monitor *mon, const QDict *qdict) { int size = qdict_get_int(qdict, "size"); @@ -1700,28 +1656,6 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str) qapi_free_ObjectPropertyInfoList(start); } -void sendkey_completion(ReadLineState *rs, int nb_args, const char *str) -{ - int i; - char *sep; - size_t len; - - if (nb_args != 2) { - return; - } - sep = strrchr(str, '-'); - if (sep) { - str = sep + 1; - } - len = strlen(str); - readline_set_completion_index(rs, len); - for (i = 0; i < Q_KEY_CODE__MAX; i++) { - if (!strncmp(str, QKeyCode_str(i), len)) { - readline_add_completion(rs, QKeyCode_str(i)); - } - } -} - void set_link_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; diff --git a/ui/meson.build b/ui/meson.build index 9194ea335b..612ea2325b 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -14,6 +14,7 @@ softmmu_ss.add(files( 'kbd-state.c', 'keymaps.c', 'qemu-pixman.c', + 'ui-hmp-cmds.c', 'ui-qmp-cmds.c', 'util.c', )) diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c new file mode 100644 index 0000000000..4af92f8eaf --- /dev/null +++ b/ui/ui-hmp-cmds.c @@ -0,0 +1,422 @@ +/* + * HMP commands related to UI + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#ifdef CONFIG_SPICE +#include +#endif +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/qapi-commands-ui.h" +#include "qapi/qmp/qdict.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "ui/input.h" + +static int mouse_button_state; + +void hmp_mouse_move(Monitor *mon, const QDict *qdict) +{ + int dx, dy, dz, button; + const char *dx_str = qdict_get_str(qdict, "dx_str"); + const char *dy_str = qdict_get_str(qdict, "dy_str"); + const char *dz_str = qdict_get_try_str(qdict, "dz_str"); + + dx = strtol(dx_str, NULL, 0); + dy = strtol(dy_str, NULL, 0); + qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); + qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); + + if (dz_str) { + dz = strtol(dz_str, NULL, 0); + if (dz != 0) { + button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; + qemu_input_queue_btn(NULL, button, true); + qemu_input_event_sync(); + qemu_input_queue_btn(NULL, button, false); + } + } + qemu_input_event_sync(); +} + +void hmp_mouse_button(Monitor *mon, const QDict *qdict) +{ + static uint32_t bmap[INPUT_BUTTON__MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + }; + int button_state = qdict_get_int(qdict, "button_state"); + + if (mouse_button_state == button_state) { + return; + } + qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state); + qemu_input_event_sync(); + mouse_button_state = button_state; +} + +void hmp_info_mice(Monitor *mon, const QDict *qdict) +{ + MouseInfoList *mice_list, *mouse; + + mice_list = qmp_query_mice(NULL); + if (!mice_list) { + monitor_printf(mon, "No mouse devices connected\n"); + return; + } + + for (mouse = mice_list; mouse; mouse = mouse->next) { + monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n", + mouse->value->current ? '*' : ' ', + mouse->value->index, mouse->value->name, + mouse->value->absolute ? " (absolute)" : ""); + } + + qapi_free_MouseInfoList(mice_list); +} + +#ifdef CONFIG_VNC +/* Helper for hmp_info_vnc_clients, _servers */ +static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info, + const char *name) +{ + monitor_printf(mon, " %s: %s:%s (%s%s)\n", + name, + info->host, + info->service, + NetworkAddressFamily_str(info->family), + info->websocket ? " (Websocket)" : ""); +} + +/* Helper displaying and auth and crypt info */ +static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent, + VncPrimaryAuth auth, + VncVencryptSubAuth *vencrypt) +{ + monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent, + VncPrimaryAuth_str(auth), + vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none"); +} + +static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client) +{ + while (client) { + VncClientInfo *cinfo = client->value; + + hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client"); + monitor_printf(mon, " x509_dname: %s\n", + cinfo->x509_dname ?: "none"); + monitor_printf(mon, " sasl_username: %s\n", + cinfo->sasl_username ?: "none"); + + client = client->next; + } +} + +static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server) +{ + while (server) { + VncServerInfo2 *sinfo = server->value; + hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server"); + hmp_info_vnc_authcrypt(mon, " ", sinfo->auth, + sinfo->has_vencrypt ? &sinfo->vencrypt : NULL); + server = server->next; + } +} + +void hmp_info_vnc(Monitor *mon, const QDict *qdict) +{ + VncInfo2List *info2l, *info2l_head; + Error *err = NULL; + + info2l = qmp_query_vnc_servers(&err); + info2l_head = info2l; + if (hmp_handle_error(mon, err)) { + return; + } + if (!info2l) { + monitor_printf(mon, "None\n"); + return; + } + + while (info2l) { + VncInfo2 *info = info2l->value; + monitor_printf(mon, "%s:\n", info->id); + hmp_info_vnc_servers(mon, info->server); + hmp_info_vnc_clients(mon, info->clients); + if (!info->server) { + /* + * The server entry displays its auth, we only need to + * display in the case of 'reverse' connections where + * there's no server. + */ + hmp_info_vnc_authcrypt(mon, " ", info->auth, + info->has_vencrypt ? &info->vencrypt : NULL); + } + if (info->display) { + monitor_printf(mon, " Display: %s\n", info->display); + } + info2l = info2l->next; + } + + qapi_free_VncInfo2List(info2l_head); + +} +#endif + +#ifdef CONFIG_SPICE +void hmp_info_spice(Monitor *mon, const QDict *qdict) +{ + SpiceChannelList *chan; + SpiceInfo *info; + const char *channel_name; + static const char *const channel_names[] = { + [SPICE_CHANNEL_MAIN] = "main", + [SPICE_CHANNEL_DISPLAY] = "display", + [SPICE_CHANNEL_INPUTS] = "inputs", + [SPICE_CHANNEL_CURSOR] = "cursor", + [SPICE_CHANNEL_PLAYBACK] = "playback", + [SPICE_CHANNEL_RECORD] = "record", + [SPICE_CHANNEL_TUNNEL] = "tunnel", + [SPICE_CHANNEL_SMARTCARD] = "smartcard", + [SPICE_CHANNEL_USBREDIR] = "usbredir", + [SPICE_CHANNEL_PORT] = "port", + [SPICE_CHANNEL_WEBDAV] = "webdav", + }; + + info = qmp_query_spice(NULL); + + if (!info->enabled) { + monitor_printf(mon, "Server: disabled\n"); + goto out; + } + + monitor_printf(mon, "Server:\n"); + if (info->has_port) { + monitor_printf(mon, " address: %s:%" PRId64 "\n", + info->host, info->port); + } + if (info->has_tls_port) { + monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", + info->host, info->tls_port); + } + monitor_printf(mon, " migrated: %s\n", + info->migrated ? "true" : "false"); + monitor_printf(mon, " auth: %s\n", info->auth); + monitor_printf(mon, " compiled: %s\n", info->compiled_version); + monitor_printf(mon, " mouse-mode: %s\n", + SpiceQueryMouseMode_str(info->mouse_mode)); + + if (!info->has_channels || info->channels == NULL) { + monitor_printf(mon, "Channels: none\n"); + } else { + for (chan = info->channels; chan; chan = chan->next) { + monitor_printf(mon, "Channel:\n"); + monitor_printf(mon, " address: %s:%s%s\n", + chan->value->host, chan->value->port, + chan->value->tls ? " [tls]" : ""); + monitor_printf(mon, " session: %" PRId64 "\n", + chan->value->connection_id); + monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n", + chan->value->channel_type, chan->value->channel_id); + + channel_name = "unknown"; + if (chan->value->channel_type > 0 && + chan->value->channel_type < ARRAY_SIZE(channel_names) && + channel_names[chan->value->channel_type]) { + channel_name = channel_names[chan->value->channel_type]; + } + + monitor_printf(mon, " channel name: %s\n", channel_name); + } + } + +out: + qapi_free_SpiceInfo(info); +} +#endif + +void hmp_set_password(Monitor *mon, const QDict *qdict) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *password = qdict_get_str(qdict, "password"); + const char *display = qdict_get_try_str(qdict, "display"); + const char *connected = qdict_get_try_str(qdict, "connected"); + Error *err = NULL; + + SetPasswordOptions opts = { + .password = (char *)password, + .has_connected = !!connected, + }; + + opts.connected = qapi_enum_parse(&SetPasswordAction_lookup, connected, + SET_PASSWORD_ACTION_KEEP, &err); + if (err) { + goto out; + } + + opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol, + DISPLAY_PROTOCOL_VNC, &err); + if (err) { + goto out; + } + + if (opts.protocol == DISPLAY_PROTOCOL_VNC) { + opts.u.vnc.display = (char *)display; + } + + qmp_set_password(&opts, &err); + +out: + hmp_handle_error(mon, err); +} + +void hmp_expire_password(Monitor *mon, const QDict *qdict) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *whenstr = qdict_get_str(qdict, "time"); + const char *display = qdict_get_try_str(qdict, "display"); + Error *err = NULL; + + ExpirePasswordOptions opts = { + .time = (char *)whenstr, + }; + + opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol, + DISPLAY_PROTOCOL_VNC, &err); + if (err) { + goto out; + } + + if (opts.protocol == DISPLAY_PROTOCOL_VNC) { + opts.u.vnc.display = (char *)display; + } + + qmp_expire_password(&opts, &err); + +out: + hmp_handle_error(mon, err); +} + +void hmp_sendkey(Monitor *mon, const QDict *qdict) +{ + const char *keys = qdict_get_str(qdict, "keys"); + KeyValue *v = NULL; + KeyValueList *head = NULL, **tail = &head; + int has_hold_time = qdict_haskey(qdict, "hold-time"); + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); + Error *err = NULL; + const char *separator; + int keyname_len; + + while (1) { + separator = qemu_strchrnul(keys, '-'); + keyname_len = separator - keys; + + /* Be compatible with old interface, convert user inputted "<" */ + if (keys[0] == '<' && keyname_len == 1) { + keys = "less"; + keyname_len = 4; + } + + v = g_malloc0(sizeof(*v)); + + if (strstart(keys, "0x", NULL)) { + const char *endp; + int value; + + if (qemu_strtoi(keys, &endp, 0, &value) < 0) { + goto err_out; + } + assert(endp <= keys + keyname_len); + if (endp != keys + keyname_len) { + goto err_out; + } + v->type = KEY_VALUE_KIND_NUMBER; + v->u.number.data = value; + } else { + int idx = index_from_key(keys, keyname_len); + if (idx == Q_KEY_CODE__MAX) { + goto err_out; + } + v->type = KEY_VALUE_KIND_QCODE; + v->u.qcode.data = idx; + } + QAPI_LIST_APPEND(tail, v); + v = NULL; + + if (!*separator) { + break; + } + keys = separator + 1; + } + + qmp_send_key(head, has_hold_time, hold_time, &err); + hmp_handle_error(mon, err); + +out: + qapi_free_KeyValue(v); + qapi_free_KeyValueList(head); + return; + +err_out: + monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys); + goto out; +} + +void sendkey_completion(ReadLineState *rs, int nb_args, const char *str) +{ + int i; + char *sep; + size_t len; + + if (nb_args != 2) { + return; + } + sep = strrchr(str, '-'); + if (sep) { + str = sep + 1; + } + len = strlen(str); + readline_set_completion_index(rs, len); + for (i = 0; i < Q_KEY_CODE__MAX; i++) { + if (!strncmp(str, QKeyCode_str(i), len)) { + readline_add_completion(rs, QKeyCode_str(i)); + } + } +} + +void coroutine_fn +hmp_screendump(Monitor *mon, const QDict *qdict) +{ + const char *filename = qdict_get_str(qdict, "filename"); + const char *id = qdict_get_try_str(qdict, "device"); + int64_t head = qdict_get_try_int(qdict, "head", 0); + const char *input_format = qdict_get_try_str(qdict, "format"); + Error *err = NULL; + ImageFormat format; + + format = qapi_enum_parse(&ImageFormat_lookup, input_format, + IMAGE_FORMAT_PPM, &err); + if (err) { + goto end; + } + + qmp_screendump(filename, id, id != NULL, head, + input_format != NULL, format, &err); +end: + hmp_handle_error(mon, err); +} From f8f2e9a859a1450756972266b0d6f4c081e6486c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:16 +0100 Subject: [PATCH 119/814] ui: Improve "change vnc" error reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from monitor_printf() to error_setg() and hmp_handle_error(). This makes "this is an error" more obvious both in the source and in the monitor, where hmp_handle_error() prefixes the message with "Error: ". Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-13-armbru@redhat.com> --- monitor/hmp-cmds.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c4f161a596..4340e71c90 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -1097,9 +1097,8 @@ void hmp_change(Monitor *mon, const QDict *qdict) #ifdef CONFIG_VNC if (strcmp(device, "vnc") == 0) { if (read_only) { - monitor_printf(mon, - "Parameter 'read-only-mode' is invalid for VNC\n"); - return; + error_setg(&err, "Parameter 'read-only-mode' is invalid for VNC"); + goto end; } if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) { @@ -1111,7 +1110,8 @@ void hmp_change(Monitor *mon, const QDict *qdict) qmp_change_vnc_password(arg, &err); } } else { - monitor_printf(mon, "Expected 'password' after 'vnc'\n"); + error_setg(&err, "Expected 'password' after 'vnc'"); + goto end; } } else #endif From f916a1751e735d3202a2dfc051d324a206831b69 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:17 +0100 Subject: [PATCH 120/814] ui: Factor out hmp_change_vnc(), and move to ui/ui-hmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-14-armbru@redhat.com> --- include/monitor/hmp.h | 5 +++++ monitor/hmp-cmds.c | 30 ++---------------------------- monitor/qmp-cmds.c | 2 +- ui/ui-hmp-cmds.c | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index b228a406f3..df89eac22a 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -73,6 +73,11 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict); void hmp_set_password(Monitor *mon, const QDict *qdict); void hmp_expire_password(Monitor *mon, const QDict *qdict); void hmp_change(Monitor *mon, const QDict *qdict); +#ifdef CONFIG_VNC +void hmp_change_vnc(Monitor *mon, const char *device, const char *target, + const char *arg, const char *read_only, bool force, + Error **errp); +#endif void hmp_migrate(Monitor *mon, const QDict *qdict); void hmp_device_add(Monitor *mon, const QDict *qdict); void hmp_device_del(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 4340e71c90..1dba973092 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -25,7 +25,7 @@ #include "qemu/timer.h" #include "qemu/sockets.h" #include "qemu/help_option.h" -#include "monitor/monitor-internal.h" +#include "monitor/monitor.h" #include "qapi/error.h" #include "qapi/clone-visitor.h" #include "qapi/opts-visitor.h" @@ -41,7 +41,6 @@ #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" -#include "qapi/qapi-commands-ui.h" #include "qapi/qapi-commands-virtio.h" #include "qapi/qapi-visit-virtio.h" #include "qapi/qapi-visit-net.h" @@ -1075,15 +1074,6 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -#ifdef CONFIG_VNC -static void hmp_change_read_arg(void *opaque, const char *password, - void *readline_opaque) -{ - qmp_change_vnc_password(password, NULL); - monitor_read_command(opaque, 1); -} -#endif - void hmp_change(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -1096,23 +1086,7 @@ void hmp_change(Monitor *mon, const QDict *qdict) #ifdef CONFIG_VNC if (strcmp(device, "vnc") == 0) { - if (read_only) { - error_setg(&err, "Parameter 'read-only-mode' is invalid for VNC"); - goto end; - } - if (strcmp(target, "passwd") == 0 || - strcmp(target, "password") == 0) { - if (!arg) { - MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); - monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); - return; - } else { - qmp_change_vnc_password(arg, &err); - } - } else { - error_setg(&err, "Expected 'password' after 'vnc'"); - goto end; - } + hmp_change_vnc(mon, device, target, arg, read_only, force, &err); } else #endif { diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index b5b736761a..14f0f78e51 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -168,7 +168,7 @@ void qmp_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) { - static struct { + static const struct { const char *name; bool (*add_client)(int fd, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp); diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c index 4af92f8eaf..8ae96749f3 100644 --- a/ui/ui-hmp-cmds.c +++ b/ui/ui-hmp-cmds.c @@ -18,7 +18,8 @@ #include #endif #include "monitor/hmp.h" -#include "monitor/monitor.h" +#include "monitor/monitor-internal.h" +#include "qapi/error.h" #include "qapi/qapi-commands-ui.h" #include "qapi/qmp/qdict.h" #include "qemu/cutils.h" @@ -311,6 +312,38 @@ out: hmp_handle_error(mon, err); } +#ifdef CONFIG_VNC +static void hmp_change_read_arg(void *opaque, const char *password, + void *readline_opaque) +{ + qmp_change_vnc_password(password, NULL); + monitor_read_command(opaque, 1); +} + +void hmp_change_vnc(Monitor *mon, const char *device, const char *target, + const char *arg, const char *read_only, bool force, + Error **errp) +{ + if (read_only) { + error_setg(errp, "Parameter 'read-only-mode' is invalid for VNC"); + return; + } + if (strcmp(target, "passwd") == 0 || + strcmp(target, "password") == 0) { + if (!arg) { + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); + monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); + return; + } else { + qmp_change_vnc_password(arg, errp); + } + } else { + error_setg(errp, "Expected 'password' after 'vnc'"); + return; + } +} +#endif + void hmp_sendkey(Monitor *mon, const QDict *qdict) { const char *keys = qdict_get_str(qdict, "keys"); From bcaf1fde57cfcb8952a8778ede0d4cf4136420b6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:18 +0100 Subject: [PATCH 121/814] ui: Reduce nesting in hmp_change_vnc() slightly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transform if (good) { do stuff } else { handle error } to if (!good) { handle error return; } do stuff Signed-off-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230109190321.1056914-15-armbru@redhat.com> --- ui/ui-hmp-cmds.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c index 8ae96749f3..7ca80c8626 100644 --- a/ui/ui-hmp-cmds.c +++ b/ui/ui-hmp-cmds.c @@ -328,19 +328,16 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target, error_setg(errp, "Parameter 'read-only-mode' is invalid for VNC"); return; } - if (strcmp(target, "passwd") == 0 || - strcmp(target, "password") == 0) { - if (!arg) { - MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); - monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); - return; - } else { - qmp_change_vnc_password(arg, errp); - } - } else { + if (strcmp(target, "passwd") && strcmp(target, "password")) { error_setg(errp, "Expected 'password' after 'vnc'"); return; } + if (!arg) { + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); + monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); + } else { + qmp_change_vnc_password(arg, errp); + } } #endif From 006e79cdf4273b52a854f36b119ebd2ea954ea92 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:19 +0100 Subject: [PATCH 122/814] ui: Don't check for mode change after mouse_set error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hmp_mouse_set() doesn't bail out when it can't find a mouse. Harmless, since qemu_input_check_mode_change() should be a no-op then. Clean it up anyway. Signed-off-by: Markus Armbruster Message-Id: <20230109190321.1056914-16-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé --- ui/input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/input.c b/ui/input.c index 8f4a87d1d7..d1c7605238 100644 --- a/ui/input.c +++ b/ui/input.c @@ -616,6 +616,7 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict) if (!found) { error_report("Mouse at index '%d' not found", index); + return; } qemu_input_check_mode_change(); From ec843b97f2c02b85115c7c5c8799ea4d02ddfba7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:20 +0100 Subject: [PATCH 123/814] ui: Split hmp_mouse_set() and move the HMP part to ui/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20230109190321.1056914-17-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé --- include/monitor/hmp.h | 1 + include/ui/console.h | 2 +- monitor/misc.c | 1 - ui/input.c | 15 +++++++-------- ui/ui-hmp-cmds.c | 8 ++++++++ 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index df89eac22a..8688769a27 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -88,6 +88,7 @@ void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); void hmp_mouse_move(Monitor *mon, const QDict *qdict); void hmp_mouse_button(Monitor *mon, const QDict *qdict); +void hmp_mouse_set(Monitor *mon, const QDict *qdict); void hmp_sendkey(Monitor *mon, const QDict *qdict); void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict); diff --git a/include/ui/console.h b/include/ui/console.h index e400ee9fa7..8e6cf782a1 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -65,7 +65,7 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); void kbd_put_ledstate(int ledstate); -void hmp_mouse_set(Monitor *mon, const QDict *qdict); +bool qemu_mouse_set(int index, Error **errp); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ diff --git a/monitor/misc.c b/monitor/misc.c index 3d68940d28..50cb9f008b 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -33,7 +33,6 @@ #include "ui/qemu-spice.h" #include "qemu/config-file.h" #include "qemu/ctype.h" -#include "ui/console.h" #include "audio/audio.h" #include "disas/disas.h" #include "qemu/timer.h" diff --git a/ui/input.c b/ui/input.c index d1c7605238..7048810a57 100644 --- a/ui/input.c +++ b/ui/input.c @@ -2,8 +2,6 @@ #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qapi-commands-ui.h" -#include "qapi/qmp/qdict.h" -#include "qemu/error-report.h" #include "trace.h" #include "ui/input.h" #include "ui/console.h" @@ -594,10 +592,9 @@ MouseInfoList *qmp_query_mice(Error **errp) return mice_list; } -void hmp_mouse_set(Monitor *mon, const QDict *qdict) +bool qemu_mouse_set(int index, Error **errp) { QemuInputHandlerState *s; - int index = qdict_get_int(qdict, "index"); int found = 0; QTAILQ_FOREACH(s, &handlers, node) { @@ -606,8 +603,9 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict) } if (!(s->handler->mask & (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) { - error_report("Input device '%s' is not a mouse", s->handler->name); - return; + error_setg(errp, "Input device '%s' is not a mouse", + s->handler->name); + return false; } found = 1; qemu_input_handler_activate(s); @@ -615,9 +613,10 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict) } if (!found) { - error_report("Mouse at index '%d' not found", index); - return; + error_setg(errp, "Mouse at index '%d' not found", index); + return false; } qemu_input_check_mode_change(); + return true; } diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c index 7ca80c8626..5c456ecc02 100644 --- a/ui/ui-hmp-cmds.c +++ b/ui/ui-hmp-cmds.c @@ -69,6 +69,14 @@ void hmp_mouse_button(Monitor *mon, const QDict *qdict) mouse_button_state = button_state; } +void hmp_mouse_set(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qemu_mouse_set(qdict_get_int(qdict, "index"), &err); + hmp_handle_error(mon, err); +} + void hmp_info_mice(Monitor *mon, const QDict *qdict) { MouseInfoList *mice_list, *mouse; From a0506b7c8fc72f7bca272647f359d76cc40a02c1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jan 2023 20:03:21 +0100 Subject: [PATCH 124/814] ui: Simplify control flow in qemu_mouse_set() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20230109190321.1056914-18-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé --- ui/input.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/ui/input.c b/ui/input.c index 7048810a57..f2d1e7a3a7 100644 --- a/ui/input.c +++ b/ui/input.c @@ -595,28 +595,26 @@ MouseInfoList *qmp_query_mice(Error **errp) bool qemu_mouse_set(int index, Error **errp) { QemuInputHandlerState *s; - int found = 0; QTAILQ_FOREACH(s, &handlers, node) { - if (s->id != index) { - continue; + if (s->id == index) { + break; } - if (!(s->handler->mask & (INPUT_EVENT_MASK_REL | - INPUT_EVENT_MASK_ABS))) { - error_setg(errp, "Input device '%s' is not a mouse", - s->handler->name); - return false; - } - found = 1; - qemu_input_handler_activate(s); - break; } - if (!found) { + if (!s) { error_setg(errp, "Mouse at index '%d' not found", index); return false; } + if (!(s->handler->mask & (INPUT_EVENT_MASK_REL | + INPUT_EVENT_MASK_ABS))) { + error_setg(errp, "Input device '%s' is not a mouse", + s->handler->name); + return false; + } + + qemu_input_handler_activate(s); qemu_input_check_mode_change(); return true; } From 753ae97abc7459e69d48712355118fb54268f8cb Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:17 +0800 Subject: [PATCH 125/814] hw/char: riscv_htif: Avoid using magic numbers The Spike HTIF is poorly documented. The only relevant info we can get from the internet is from Andrew Waterman at [1]. Add a comment block before htif_handle_tohost_write() to explain the tohost register format, and use meaningful macros instead of magic numbers in the codes. While we are here, correct 2 multi-line comment blocks that have wrong format. Link: https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754 [1] Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-2-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 72 ++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index 6577f0e640..088556bb04 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -38,6 +38,16 @@ } \ } while (0) +#define HTIF_DEV_SHIFT 56 +#define HTIF_CMD_SHIFT 48 + +#define HTIF_DEV_SYSTEM 0 +#define HTIF_DEV_CONSOLE 1 + +#define HTIF_SYSTEM_CMD_SYSCALL 0 +#define HTIF_CONSOLE_CMD_GETC 0 +#define HTIF_CONSOLE_CMD_PUTC 1 + static uint64_t fromhost_addr, tohost_addr; static int address_symbol_set; @@ -81,9 +91,11 @@ static void htif_recv(void *opaque, const uint8_t *buf, int size) return; } - /* TODO - we need to check whether mfromhost is zero which indicates - the device is ready to receive. The current implementation - will drop characters */ + /* + * TODO - we need to check whether mfromhost is zero which indicates + * the device is ready to receive. The current implementation + * will drop characters + */ uint64_t val_written = htifstate->pending_read; uint64_t resp = 0x100 | *buf; @@ -110,10 +122,30 @@ static int htif_be_change(void *opaque) return 0; } +/* + * See below the tohost register format. + * + * Bits 63:56 indicate the "device". + * Bits 55:48 indicate the "command". + * + * Device 0 is the syscall device, which is used to emulate Unixy syscalls. + * It only implements command 0, which has two subfunctions: + * - If bit 0 is clear, then bits 47:0 represent a pointer to a struct + * describing the syscall. + * - If bit 1 is set, then bits 47:1 represent an exit code, with a zero + * value indicating success and other values indicating failure. + * + * Device 1 is the blocking character device. + * - Command 0 reads a character + * - Command 1 writes a character from the 8 LSBs of tohost + * + * For RV32, the tohost register is zero-extended, so only device=0 and + * command=0 (i.e. HTIF syscalls/exit codes) are supported. + */ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) { - uint8_t device = val_written >> 56; - uint8_t cmd = val_written >> 48; + uint8_t device = val_written >> HTIF_DEV_SHIFT; + uint8_t cmd = val_written >> HTIF_CMD_SHIFT; uint64_t payload = val_written & 0xFFFFFFFFFFFFULL; int resp = 0; @@ -125,9 +157,9 @@ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) * 0: riscv-tests Pass/Fail Reporting Only (no syscall proxy) * 1: Console */ - if (unlikely(device == 0x0)) { + if (unlikely(device == HTIF_DEV_SYSTEM)) { /* frontend syscall handler, shutdown and exit code support */ - if (cmd == 0x0) { + if (cmd == HTIF_SYSTEM_CMD_SYSCALL) { if (payload & 0x1) { /* exit code */ int exit_code = payload >> 1; @@ -138,14 +170,14 @@ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) } else { qemu_log("HTIF device %d: unknown command\n", device); } - } else if (likely(device == 0x1)) { + } else if (likely(device == HTIF_DEV_CONSOLE)) { /* HTIF Console */ - if (cmd == 0x0) { + if (cmd == HTIF_CONSOLE_CMD_GETC) { /* this should be a queue, but not yet implemented as such */ htifstate->pending_read = val_written; htifstate->env->mtohost = 0; /* clear to indicate we read */ return; - } else if (cmd == 0x1) { + } else if (cmd == HTIF_CONSOLE_CMD_PUTC) { qemu_chr_fe_write(&htifstate->chr, (uint8_t *)&payload, 1); resp = 0x100 | (uint8_t)payload; } else { @@ -157,15 +189,15 @@ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) " payload: %016" PRIx64, device, cmd, payload & 0xFF, payload); } /* - * - latest bbl does not set fromhost to 0 if there is a value in tohost - * - with this code enabled, qemu hangs waiting for fromhost to go to 0 - * - with this code disabled, qemu works with bbl priv v1.9.1 and v1.10 - * - HTIF needs protocol documentation and a more complete state machine - - while (!htifstate->fromhost_inprogress && - htifstate->env->mfromhost != 0x0) { - } - */ + * Latest bbl does not set fromhost to 0 if there is a value in tohost. + * With this code enabled, qemu hangs waiting for fromhost to go to 0. + * With this code disabled, qemu works with bbl priv v1.9.1 and v1.10. + * HTIF needs protocol documentation and a more complete state machine. + * + * while (!htifstate->fromhost_inprogress && + * htifstate->env->mfromhost != 0x0) { + * } + */ htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); htifstate->env->mtohost = 0; /* clear to indicate we read */ } @@ -196,7 +228,7 @@ static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size) /* CPU wrote to an HTIF register */ static void htif_mm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) + uint64_t value, unsigned size) { HTIFState *htifstate = opaque; if (addr == TOHOST_OFFSET1) { From bc9c3b18626fbfe9eb8f37438b5fbb2f901c2460 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:18 +0800 Subject: [PATCH 126/814] hw/char: riscv_htif: Drop {to, from}host_size in HTIFState These are not used anywhere. Drop them. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-3-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- include/hw/char/riscv_htif.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index f888ac1b30..3eccc1914f 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -33,8 +33,6 @@ typedef struct HTIFState { hwaddr tohost_offset; hwaddr fromhost_offset; - uint64_t tohost_size; - uint64_t fromhost_size; MemoryRegion mmio; MemoryRegion *address_space; MemoryRegion *main_mem; From dc6882464161a7bf77c8b847cef6d4f2f9066361 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:19 +0800 Subject: [PATCH 127/814] hw/char: riscv_htif: Drop useless assignment of memory region struct HTIFState has 3 members for address space and memory region, and are initialized during htif_mm_init(). But they are actually useless. Drop them. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-4-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 7 ++----- hw/riscv/spike.c | 5 ++--- include/hw/char/riscv_htif.h | 7 ++----- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index 088556bb04..e7e319ca1d 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -265,8 +265,8 @@ bool htif_uses_elf_symbols(void) return (address_symbol_set == 3) ? true : false; } -HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem, - CPURISCVState *env, Chardev *chr, uint64_t nonelf_base) +HTIFState *htif_mm_init(MemoryRegion *address_space, CPURISCVState *env, + Chardev *chr, uint64_t nonelf_base) { uint64_t base, size, tohost_offset, fromhost_offset; @@ -281,9 +281,6 @@ HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem, fromhost_offset = fromhost_addr - base; HTIFState *s = g_new0(HTIFState, 1); - s->address_space = address_space; - s->main_mem = main_mem; - s->main_mem_ram_ptr = memory_region_get_ram_ptr(main_mem); s->env = env; s->tohost_offset = tohost_offset; s->fromhost_offset = fromhost_offset; diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 13946acf0d..bc4953cf4a 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -316,9 +316,8 @@ static void spike_board_init(MachineState *machine) fdt_load_addr); /* initialize HTIF using symbols found in load_kernel */ - htif_mm_init(system_memory, mask_rom, - &s->soc[0].harts[0].env, serial_hd(0), - memmap[SPIKE_HTIF].base); + htif_mm_init(system_memory, &s->soc[0].harts[0].env, + serial_hd(0), memmap[SPIKE_HTIF].base); } static void spike_machine_instance_init(Object *obj) diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index 3eccc1914f..6d172ebd6d 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -34,9 +34,6 @@ typedef struct HTIFState { hwaddr tohost_offset; hwaddr fromhost_offset; MemoryRegion mmio; - MemoryRegion *address_space; - MemoryRegion *main_mem; - void *main_mem_ram_ptr; CPURISCVState *env; CharBackend chr; @@ -54,7 +51,7 @@ void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, bool htif_uses_elf_symbols(void); /* legacy pre qom */ -HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem, - CPURISCVState *env, Chardev *chr, uint64_t nonelf_base); +HTIFState *htif_mm_init(MemoryRegion *address_space, CPURISCVState *env, + Chardev *chr, uint64_t nonelf_base); #endif From dadee9e3ce6ee6aad36fe3027eaa0f947358f812 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:20 +0800 Subject: [PATCH 128/814] hw/char: riscv_htif: Use conventional 's' for HTIFState QEMU source codes tend to use 's' to represent the hardware state. Let's use it for HTIFState. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-5-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 64 ++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index e7e319ca1d..f28976b110 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -85,7 +85,7 @@ static int htif_can_recv(void *opaque) */ static void htif_recv(void *opaque, const uint8_t *buf, int size) { - HTIFState *htifstate = opaque; + HTIFState *s = opaque; if (size != 1) { return; @@ -97,10 +97,10 @@ static void htif_recv(void *opaque, const uint8_t *buf, int size) * will drop characters */ - uint64_t val_written = htifstate->pending_read; + uint64_t val_written = s->pending_read; uint64_t resp = 0x100 | *buf; - htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); + s->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); } /* @@ -142,7 +142,7 @@ static int htif_be_change(void *opaque) * For RV32, the tohost register is zero-extended, so only device=0 and * command=0 (i.e. HTIF syscalls/exit codes) are supported. */ -static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) +static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written) { uint8_t device = val_written >> HTIF_DEV_SHIFT; uint8_t cmd = val_written >> HTIF_CMD_SHIFT; @@ -174,11 +174,11 @@ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) /* HTIF Console */ if (cmd == HTIF_CONSOLE_CMD_GETC) { /* this should be a queue, but not yet implemented as such */ - htifstate->pending_read = val_written; - htifstate->env->mtohost = 0; /* clear to indicate we read */ + s->pending_read = val_written; + s->env->mtohost = 0; /* clear to indicate we read */ return; } else if (cmd == HTIF_CONSOLE_CMD_PUTC) { - qemu_chr_fe_write(&htifstate->chr, (uint8_t *)&payload, 1); + qemu_chr_fe_write(&s->chr, (uint8_t *)&payload, 1); resp = 0x100 | (uint8_t)payload; } else { qemu_log("HTIF device %d: unknown command\n", device); @@ -194,31 +194,31 @@ static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) * With this code disabled, qemu works with bbl priv v1.9.1 and v1.10. * HTIF needs protocol documentation and a more complete state machine. * - * while (!htifstate->fromhost_inprogress && - * htifstate->env->mfromhost != 0x0) { + * while (!s->fromhost_inprogress && + * s->env->mfromhost != 0x0) { * } */ - htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); - htifstate->env->mtohost = 0; /* clear to indicate we read */ + s->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); + s->env->mtohost = 0; /* clear to indicate we read */ } -#define TOHOST_OFFSET1 (htifstate->tohost_offset) -#define TOHOST_OFFSET2 (htifstate->tohost_offset + 4) -#define FROMHOST_OFFSET1 (htifstate->fromhost_offset) -#define FROMHOST_OFFSET2 (htifstate->fromhost_offset + 4) +#define TOHOST_OFFSET1 (s->tohost_offset) +#define TOHOST_OFFSET2 (s->tohost_offset + 4) +#define FROMHOST_OFFSET1 (s->fromhost_offset) +#define FROMHOST_OFFSET2 (s->fromhost_offset + 4) /* CPU wants to read an HTIF register */ static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size) { - HTIFState *htifstate = opaque; + HTIFState *s = opaque; if (addr == TOHOST_OFFSET1) { - return htifstate->env->mtohost & 0xFFFFFFFF; + return s->env->mtohost & 0xFFFFFFFF; } else if (addr == TOHOST_OFFSET2) { - return (htifstate->env->mtohost >> 32) & 0xFFFFFFFF; + return (s->env->mtohost >> 32) & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET1) { - return htifstate->env->mfromhost & 0xFFFFFFFF; + return s->env->mfromhost & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET2) { - return (htifstate->env->mfromhost >> 32) & 0xFFFFFFFF; + return (s->env->mfromhost >> 32) & 0xFFFFFFFF; } else { qemu_log("Invalid htif read: address %016" PRIx64 "\n", (uint64_t)addr); @@ -230,25 +230,25 @@ static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size) static void htif_mm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - HTIFState *htifstate = opaque; + HTIFState *s = opaque; if (addr == TOHOST_OFFSET1) { - if (htifstate->env->mtohost == 0x0) { - htifstate->allow_tohost = 1; - htifstate->env->mtohost = value & 0xFFFFFFFF; + if (s->env->mtohost == 0x0) { + s->allow_tohost = 1; + s->env->mtohost = value & 0xFFFFFFFF; } else { - htifstate->allow_tohost = 0; + s->allow_tohost = 0; } } else if (addr == TOHOST_OFFSET2) { - if (htifstate->allow_tohost) { - htifstate->env->mtohost |= value << 32; - htif_handle_tohost_write(htifstate, htifstate->env->mtohost); + if (s->allow_tohost) { + s->env->mtohost |= value << 32; + htif_handle_tohost_write(s, s->env->mtohost); } } else if (addr == FROMHOST_OFFSET1) { - htifstate->fromhost_inprogress = 1; - htifstate->env->mfromhost = value & 0xFFFFFFFF; + s->fromhost_inprogress = 1; + s->env->mfromhost = value & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET2) { - htifstate->env->mfromhost |= value << 32; - htifstate->fromhost_inprogress = 0; + s->env->mfromhost |= value << 32; + s->fromhost_inprogress = 0; } else { qemu_log("Invalid htif write: address %016" PRIx64 "\n", (uint64_t)addr); From 1237c2d6942709cf82b999b6f6e8624b86ac495f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:21 +0800 Subject: [PATCH 129/814] hw/char: riscv_htif: Move registers from CPUArchState to HTIFState At present for some unknown reason the HTIF registers (fromhost & tohost) are defined in the RISC-V CPUArchState. It should really be put in the HTIFState struct as it is only meaningful to HTIF. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-6-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 35 +++++++++++++++++------------------ hw/riscv/spike.c | 3 +-- include/hw/char/riscv_htif.h | 8 ++++---- target/riscv/cpu.h | 4 ---- target/riscv/machine.c | 6 ++---- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index f28976b110..3bb0a37a3e 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -100,7 +100,7 @@ static void htif_recv(void *opaque, const uint8_t *buf, int size) uint64_t val_written = s->pending_read; uint64_t resp = 0x100 | *buf; - s->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); + s->fromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); } /* @@ -175,7 +175,7 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written) if (cmd == HTIF_CONSOLE_CMD_GETC) { /* this should be a queue, but not yet implemented as such */ s->pending_read = val_written; - s->env->mtohost = 0; /* clear to indicate we read */ + s->tohost = 0; /* clear to indicate we read */ return; } else if (cmd == HTIF_CONSOLE_CMD_PUTC) { qemu_chr_fe_write(&s->chr, (uint8_t *)&payload, 1); @@ -195,11 +195,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written) * HTIF needs protocol documentation and a more complete state machine. * * while (!s->fromhost_inprogress && - * s->env->mfromhost != 0x0) { + * s->fromhost != 0x0) { * } */ - s->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); - s->env->mtohost = 0; /* clear to indicate we read */ + s->fromhost = (val_written >> 48 << 48) | (resp << 16 >> 16); + s->tohost = 0; /* clear to indicate we read */ } #define TOHOST_OFFSET1 (s->tohost_offset) @@ -212,13 +212,13 @@ static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size) { HTIFState *s = opaque; if (addr == TOHOST_OFFSET1) { - return s->env->mtohost & 0xFFFFFFFF; + return s->tohost & 0xFFFFFFFF; } else if (addr == TOHOST_OFFSET2) { - return (s->env->mtohost >> 32) & 0xFFFFFFFF; + return (s->tohost >> 32) & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET1) { - return s->env->mfromhost & 0xFFFFFFFF; + return s->fromhost & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET2) { - return (s->env->mfromhost >> 32) & 0xFFFFFFFF; + return (s->fromhost >> 32) & 0xFFFFFFFF; } else { qemu_log("Invalid htif read: address %016" PRIx64 "\n", (uint64_t)addr); @@ -232,22 +232,22 @@ static void htif_mm_write(void *opaque, hwaddr addr, { HTIFState *s = opaque; if (addr == TOHOST_OFFSET1) { - if (s->env->mtohost == 0x0) { + if (s->tohost == 0x0) { s->allow_tohost = 1; - s->env->mtohost = value & 0xFFFFFFFF; + s->tohost = value & 0xFFFFFFFF; } else { s->allow_tohost = 0; } } else if (addr == TOHOST_OFFSET2) { if (s->allow_tohost) { - s->env->mtohost |= value << 32; - htif_handle_tohost_write(s, s->env->mtohost); + s->tohost |= value << 32; + htif_handle_tohost_write(s, s->tohost); } } else if (addr == FROMHOST_OFFSET1) { s->fromhost_inprogress = 1; - s->env->mfromhost = value & 0xFFFFFFFF; + s->fromhost = value & 0xFFFFFFFF; } else if (addr == FROMHOST_OFFSET2) { - s->env->mfromhost |= value << 32; + s->fromhost |= value << 32; s->fromhost_inprogress = 0; } else { qemu_log("Invalid htif write: address %016" PRIx64 "\n", @@ -265,8 +265,8 @@ bool htif_uses_elf_symbols(void) return (address_symbol_set == 3) ? true : false; } -HTIFState *htif_mm_init(MemoryRegion *address_space, CPURISCVState *env, - Chardev *chr, uint64_t nonelf_base) +HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr, + uint64_t nonelf_base) { uint64_t base, size, tohost_offset, fromhost_offset; @@ -281,7 +281,6 @@ HTIFState *htif_mm_init(MemoryRegion *address_space, CPURISCVState *env, fromhost_offset = fromhost_addr - base; HTIFState *s = g_new0(HTIFState, 1); - s->env = env; s->tohost_offset = tohost_offset; s->fromhost_offset = fromhost_offset; s->pending_read = 0; diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index bc4953cf4a..fb4152c2a2 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -316,8 +316,7 @@ static void spike_board_init(MachineState *machine) fdt_load_addr); /* initialize HTIF using symbols found in load_kernel */ - htif_mm_init(system_memory, &s->soc[0].harts[0].env, - serial_hd(0), memmap[SPIKE_HTIF].base); + htif_mm_init(system_memory, serial_hd(0), memmap[SPIKE_HTIF].base); } static void spike_machine_instance_init(Object *obj) diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index 6d172ebd6d..55cc352331 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -23,7 +23,6 @@ #include "chardev/char.h" #include "chardev/char-fe.h" #include "exec/memory.h" -#include "target/riscv/cpu.h" #define TYPE_HTIF_UART "riscv.htif.uart" @@ -31,11 +30,12 @@ typedef struct HTIFState { int allow_tohost; int fromhost_inprogress; + uint64_t tohost; + uint64_t fromhost; hwaddr tohost_offset; hwaddr fromhost_offset; MemoryRegion mmio; - CPURISCVState *env; CharBackend chr; uint64_t pending_read; } HTIFState; @@ -51,7 +51,7 @@ void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, bool htif_uses_elf_symbols(void); /* legacy pre qom */ -HTIFState *htif_mm_init(MemoryRegion *address_space, CPURISCVState *env, - Chardev *chr, uint64_t nonelf_base); +HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr, + uint64_t nonelf_base); #endif diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f5609b62a2..61a9a40958 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -309,10 +309,6 @@ struct CPUArchState { target_ulong sscratch; target_ulong mscratch; - /* temporary htif regs */ - uint64_t mfromhost; - uint64_t mtohost; - /* Sstc CSRs */ uint64_t stimecmp; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 65a8549ec2..c6ce318cce 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -333,8 +333,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 5, - .minimum_version_id = 5, + .version_id = 6, + .minimum_version_id = 6, .post_load = riscv_cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -384,8 +384,6 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINTTL(env.sscratch, RISCVCPU), VMSTATE_UINTTL(env.mscratch, RISCVCPU), - VMSTATE_UINT64(env.mfromhost, RISCVCPU), - VMSTATE_UINT64(env.mtohost, RISCVCPU), VMSTATE_UINT64(env.stimecmp, RISCVCPU), VMSTATE_END_OF_LIST() From 03ef1899dd1194d58d51f41491ba24c87f901264 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:22 +0800 Subject: [PATCH 130/814] hw/char: riscv_htif: Remove forward declarations for non-existent variables There are forward declarations for 'vmstate_htif' and 'htif_io_ops' in riscv_htif.h however there are no definitions in the C codes. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-7-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- include/hw/char/riscv_htif.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index 55cc352331..9e8ebbe017 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -40,9 +40,6 @@ typedef struct HTIFState { uint64_t pending_read; } HTIFState; -extern const VMStateDescription vmstate_htif; -extern const MemoryRegionOps htif_io_ops; - /* HTIF symbol callback */ void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, uint64_t st_size); From a6e13e31d5c34d59c28e908f3e51cf87bc82666f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:23 +0800 Subject: [PATCH 131/814] hw/char: riscv_htif: Support console output via proxy syscall At present the HTIF proxy syscall is unsupported. On RV32, only device 0 is supported so there is no console device for RV32. The only way to implement console funtionality on RV32 is to support the SYS_WRITE syscall. With this commit, the Spike machine is able to boot the 32-bit OpenSBI generic image. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-8-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index 3bb0a37a3e..1477fc0090 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -48,6 +48,9 @@ #define HTIF_CONSOLE_CMD_GETC 0 #define HTIF_CONSOLE_CMD_PUTC 1 +/* PK system call number */ +#define PK_SYS_WRITE 64 + static uint64_t fromhost_addr, tohost_addr; static int address_symbol_set; @@ -165,7 +168,19 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written) int exit_code = payload >> 1; exit(exit_code); } else { - qemu_log_mask(LOG_UNIMP, "pk syscall proxy not supported\n"); + uint64_t syscall[8]; + cpu_physical_memory_read(payload, syscall, sizeof(syscall)); + if (syscall[0] == PK_SYS_WRITE && + syscall[1] == HTIF_DEV_CONSOLE && + syscall[3] == HTIF_CONSOLE_CMD_PUTC) { + uint8_t ch; + cpu_physical_memory_read(syscall[2], &ch, 1); + qemu_chr_fe_write(&s->chr, &ch, 1); + resp = 0x100 | (uint8_t)payload; + } else { + qemu_log_mask(LOG_UNIMP, + "pk syscall proxy not supported\n"); + } } } else { qemu_log("HTIF device %d: unknown command\n", device); From a8a7f680d25a6dc52b1a56a597563a6d6be5f8da Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:24 +0800 Subject: [PATCH 132/814] hw/riscv: spike: Remove the out-of-date comments Spike machine now supports OpenSBI plain binary bios image, so the comments are no longer valid. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-9-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index fb4152c2a2..df9f070707 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -255,11 +255,6 @@ static void spike_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, mask_rom); - /* - * Not like other RISC-V machines that use plain binary bios images, - * keeping ELF files here was intentional because BIN files don't work - * for the Spike machine as HTIF emulation depends on ELF parsing. - */ if (riscv_is_32bit(&s->soc[0])) { firmware_end_addr = riscv_find_and_load_firmware(machine, RISCV32_BIOS_BIN, memmap[SPIKE_DRAM].base, From 808faef7cd38222ac02e5876e5170c7d00982876 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 29 Dec 2022 17:18:25 +0800 Subject: [PATCH 133/814] hw/riscv/boot.c: make riscv_find_firmware() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only caller is riscv_find_and_load_firmware(), which is in the same file. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Signed-off-by: Bin Meng Message-Id: <20221221182300.307900-5-dbarboza@ventanamicro.com> Message-Id: <20221229091828.1945072-10-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 44 ++++++++++++++++++++--------------------- include/hw/riscv/boot.h | 1 - 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index ebd351c840..7361d5c0d8 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -75,6 +75,28 @@ target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, } } +static char *riscv_find_firmware(const char *firmware_filename) +{ + char *filename; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename); + if (filename == NULL) { + if (!qtest_enabled()) { + /* + * We only ship OpenSBI binary bios images in the QEMU source. + * For machines that use images other than the default bios, + * running QEMU test will complain hence let's suppress the error + * report for QEMU testing. + */ + error_report("Unable to load the RISC-V firmware \"%s\"", + firmware_filename); + exit(1); + } + } + + return filename; +} + target_ulong riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, hwaddr firmware_load_addr, @@ -104,28 +126,6 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine, return firmware_end_addr; } -char *riscv_find_firmware(const char *firmware_filename) -{ - char *filename; - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename); - if (filename == NULL) { - if (!qtest_enabled()) { - /* - * We only ship OpenSBI binary bios images in the QEMU source. - * For machines that use images other than the default bios, - * running QEMU test will complain hence let's suppress the error - * report for QEMU testing. - */ - error_report("Unable to load the RISC-V firmware \"%s\"", - firmware_filename); - exit(1); - } - } - - return filename; -} - target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb) diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 93e5f8760d..c03e4e74c5 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -37,7 +37,6 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, hwaddr firmware_load_addr, symbol_fn_t sym_cb); -char *riscv_find_firmware(const char *firmware_filename); target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb); From 9d3f7108bc43e93ceef7faa27c87eea8295c33ed Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 29 Dec 2022 17:18:26 +0800 Subject: [PATCH 134/814] hw/riscv/boot.c: introduce riscv_default_firmware_name() Some boards are duplicating the 'riscv_find_and_load_firmware' call because the 32 and 64 bits images have different names. Create a function to handle this detail instead of hardcoding it in the boards. Ideally we would bake this logic inside riscv_find_and_load_firmware(), or even create a riscv_load_default_firmware(), but at this moment we cannot infer whether the machine is running 32 or 64 bits without accessing RISCVHartArrayState, which in turn can't be accessed via the common code from boot.c. In the end we would exchange 'firmware_name' for a flag with riscv_is_32bit(), which isn't much better than what we already have today. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Signed-off-by: Bin Meng Message-Id: <20221221182300.307900-6-dbarboza@ventanamicro.com> Message-Id: <20221229091828.1945072-11-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 9 +++++++++ hw/riscv/sifive_u.c | 11 ++++------- hw/riscv/spike.c | 14 +++++--------- hw/riscv/virt.c | 10 +++------- include/hw/riscv/boot.h | 1 + 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 7361d5c0d8..e1a544b1d9 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -75,6 +75,15 @@ target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, } } +const char *riscv_default_firmware_name(RISCVHartArrayState *harts) +{ + if (riscv_is_32bit(harts)) { + return RISCV32_BIOS_BIN; + } + + return RISCV64_BIOS_BIN; +} + static char *riscv_find_firmware(const char *firmware_filename) { char *filename; diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index b40a4767e2..a58ddb36ac 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -533,6 +533,7 @@ static void sifive_u_machine_init(MachineState *machine) MemoryRegion *flash0 = g_new(MemoryRegion, 1); target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base; target_ulong firmware_end_addr, kernel_start_addr; + const char *firmware_name; uint32_t start_addr_hi32 = 0x00000000; int i; uint32_t fdt_load_addr; @@ -595,13 +596,9 @@ static void sifive_u_machine_init(MachineState *machine) break; } - if (riscv_is_32bit(&s->soc.u_cpus)) { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV32_BIOS_BIN, start_addr, NULL); - } else { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV64_BIOS_BIN, start_addr, NULL); - } + firmware_name = riscv_default_firmware_name(&s->soc.u_cpus); + firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, + start_addr, NULL); if (machine->kernel_filename) { kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index df9f070707..3c8a8de673 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -190,6 +190,7 @@ static void spike_board_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); target_ulong firmware_end_addr, kernel_start_addr; + const char *firmware_name; uint32_t fdt_load_addr; uint64_t kernel_entry; char *soc_name; @@ -255,15 +256,10 @@ static void spike_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, mask_rom); - if (riscv_is_32bit(&s->soc[0])) { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV32_BIOS_BIN, memmap[SPIKE_DRAM].base, - htif_symbol_callback); - } else { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV64_BIOS_BIN, memmap[SPIKE_DRAM].base, - htif_symbol_callback); - } + firmware_name = riscv_default_firmware_name(&s->soc[0]); + firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, + memmap[SPIKE_DRAM].base, + htif_symbol_callback); /* Load kernel */ if (machine->kernel_filename) { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..408f7a2256 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1237,6 +1237,7 @@ static void virt_machine_done(Notifier *notifier, void *data) MachineState *machine = MACHINE(s); target_ulong start_addr = memmap[VIRT_DRAM].base; target_ulong firmware_end_addr, kernel_start_addr; + const char *firmware_name = riscv_default_firmware_name(&s->soc[0]); uint32_t fdt_load_addr; uint64_t kernel_entry; @@ -1256,13 +1257,8 @@ static void virt_machine_done(Notifier *notifier, void *data) } } - if (riscv_is_32bit(&s->soc[0])) { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV32_BIOS_BIN, start_addr, NULL); - } else { - firmware_end_addr = riscv_find_and_load_firmware(machine, - RISCV64_BIOS_BIN, start_addr, NULL); - } + firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, + start_addr, NULL); /* * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index c03e4e74c5..60cf320c88 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -37,6 +37,7 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, hwaddr firmware_load_addr, symbol_fn_t sym_cb); +const char *riscv_default_firmware_name(RISCVHartArrayState *harts); target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb); From 8f6196266e607a4a014ef1a5ab05b93343f678df Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 17:18:27 +0800 Subject: [PATCH 135/814] hw/riscv/boot.c: Introduce riscv_find_firmware() Rename previous riscv_find_firmware() to riscv_find_bios(), and introduce a new riscv_find_firmware() to implement the first half part of the work done in riscv_find_and_load_firmware(). This new API is helpful for machine that wants to know the final chosen firmware file name but does not want to load it. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20221229091828.1945072-12-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 41 ++++++++++++++++++++++++++--------------- include/hw/riscv/boot.h | 2 ++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index e1a544b1d9..98b80af51b 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -84,11 +84,11 @@ const char *riscv_default_firmware_name(RISCVHartArrayState *harts) return RISCV64_BIOS_BIN; } -static char *riscv_find_firmware(const char *firmware_filename) +static char *riscv_find_bios(const char *bios_filename) { char *filename; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_filename); if (filename == NULL) { if (!qtest_enabled()) { /* @@ -97,8 +97,8 @@ static char *riscv_find_firmware(const char *firmware_filename) * running QEMU test will complain hence let's suppress the error * report for QEMU testing. */ - error_report("Unable to load the RISC-V firmware \"%s\"", - firmware_filename); + error_report("Unable to find the RISC-V BIOS \"%s\"", + bios_filename); exit(1); } } @@ -106,24 +106,35 @@ static char *riscv_find_firmware(const char *firmware_filename) return filename; } +char *riscv_find_firmware(const char *firmware_filename, + const char *default_machine_firmware) +{ + char *filename = NULL; + + if ((!firmware_filename) || (!strcmp(firmware_filename, "default"))) { + /* + * The user didn't specify -bios, or has specified "-bios default". + * That means we are going to load the OpenSBI binary included in + * the QEMU source. + */ + filename = riscv_find_bios(default_machine_firmware); + } else if (strcmp(firmware_filename, "none")) { + filename = riscv_find_bios(firmware_filename); + } + + return filename; +} + target_ulong riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, hwaddr firmware_load_addr, symbol_fn_t sym_cb) { - char *firmware_filename = NULL; + char *firmware_filename; target_ulong firmware_end_addr = firmware_load_addr; - if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) { - /* - * The user didn't specify -bios, or has specified "-bios default". - * That means we are going to load the OpenSBI binary included in - * the QEMU source. - */ - firmware_filename = riscv_find_firmware(default_machine_firmware); - } else if (strcmp(machine->firmware, "none")) { - firmware_filename = riscv_find_firmware(machine->firmware); - } + firmware_filename = riscv_find_firmware(machine->firmware, + default_machine_firmware); if (firmware_filename) { /* If not "none" load the firmware */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 60cf320c88..b273ab22f7 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -38,6 +38,8 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine, hwaddr firmware_load_addr, symbol_fn_t sym_cb); const char *riscv_default_firmware_name(RISCVHartArrayState *harts); +char *riscv_find_firmware(const char *firmware_filename, + const char *default_machine_firmware); target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb); From 71d68c48be96366fb89f7a2dd9d82dd86bcbe542 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Dec 2022 18:31:23 +0800 Subject: [PATCH 136/814] hw/riscv: spike: Decouple create_fdt() dependency to ELF loading At present create_fdt() calls htif_uses_elf_symbols() to determine whether to insert a property for the HTIF. This unfortunately creates a hidden dependency to riscv_load_{firmware,kernel} that create_fdt() must be called after the ELF {firmware,kernel} image has been loaded. Decouple such dependency be adding a new parameter to create_fdt(), whether custom HTIF base address is used. The flag will be set if non ELF {firmware,kernel} image is given by user. Signed-off-by: Bin Meng Reviewed-by: Daniel Henrique Barboza Message-Id: <20221229091828.1945072-13-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/char/riscv_htif.c | 17 +++++----- hw/riscv/spike.c | 61 ++++++++++++++++++++++++++++++------ include/hw/char/riscv_htif.h | 5 +-- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index 1477fc0090..098de50e35 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -52,20 +52,17 @@ #define PK_SYS_WRITE 64 static uint64_t fromhost_addr, tohost_addr; -static int address_symbol_set; void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, uint64_t st_size) { if (strcmp("fromhost", st_name) == 0) { - address_symbol_set |= 1; fromhost_addr = st_value; if (st_size != 8) { error_report("HTIF fromhost must be 8 bytes"); exit(1); } } else if (strcmp("tohost", st_name) == 0) { - address_symbol_set |= 2; tohost_addr = st_value; if (st_size != 8) { error_report("HTIF tohost must be 8 bytes"); @@ -275,19 +272,19 @@ static const MemoryRegionOps htif_mm_ops = { .write = htif_mm_write, }; -bool htif_uses_elf_symbols(void) -{ - return (address_symbol_set == 3) ? true : false; -} - HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr, - uint64_t nonelf_base) + uint64_t nonelf_base, bool custom_base) { uint64_t base, size, tohost_offset, fromhost_offset; - if (!htif_uses_elf_symbols()) { + if (custom_base) { fromhost_addr = nonelf_base; tohost_addr = nonelf_base + 8; + } else { + if (!fromhost_addr || !tohost_addr) { + error_report("Invalid HTIF fromhost or tohost address"); + exit(1); + } } base = MIN(tohost_addr, fromhost_addr); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 3c8a8de673..1679c325d5 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -49,7 +49,8 @@ static const MemMapEntry spike_memmap[] = { }; static void create_fdt(SpikeState *s, const MemMapEntry *memmap, - uint64_t mem_size, const char *cmdline, bool is_32_bit) + uint64_t mem_size, const char *cmdline, + bool is_32_bit, bool htif_custom_base) { void *fdt; uint64_t addr, size; @@ -77,7 +78,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_add_subnode(fdt, "/htif"); qemu_fdt_setprop_string(fdt, "/htif", "compatible", "ucb,htif0"); - if (!htif_uses_elf_symbols()) { + if (htif_custom_base) { qemu_fdt_setprop_cells(fdt, "/htif", "reg", 0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size); } @@ -183,18 +184,33 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, } } +static bool spike_test_elf_image(char *filename) +{ + Error *err = NULL; + + load_elf_hdr(filename, NULL, NULL, &err); + if (err) { + error_free(err); + return false; + } else { + return true; + } +} + static void spike_board_init(MachineState *machine) { const MemMapEntry *memmap = spike_memmap; SpikeState *s = SPIKE_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); - target_ulong firmware_end_addr, kernel_start_addr; - const char *firmware_name; + target_ulong firmware_end_addr = memmap[SPIKE_DRAM].base; + target_ulong kernel_start_addr; + char *firmware_name; uint32_t fdt_load_addr; uint64_t kernel_entry; char *soc_name; int i, base_hartid, hart_count; + bool htif_custom_base = false; /* Check socket count limit */ if (SPIKE_SOCKETS_MAX < riscv_socket_count(machine)) { @@ -256,10 +272,34 @@ static void spike_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, mask_rom); - firmware_name = riscv_default_firmware_name(&s->soc[0]); - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, - memmap[SPIKE_DRAM].base, - htif_symbol_callback); + /* Find firmware */ + firmware_name = riscv_find_firmware(machine->firmware, + riscv_default_firmware_name(&s->soc[0])); + + /* + * Test the given firmware or kernel file to see if it is an ELF image. + * If it is an ELF, we assume it contains the symbols required for + * the HTIF console, otherwise we fall back to use the custom base + * passed from device tree for the HTIF console. + */ + if (!firmware_name && !machine->kernel_filename) { + htif_custom_base = true; + } else { + if (firmware_name) { + htif_custom_base = !spike_test_elf_image(firmware_name); + } + if (!htif_custom_base && machine->kernel_filename) { + htif_custom_base = !spike_test_elf_image(machine->kernel_filename); + } + } + + /* Load firmware */ + if (firmware_name) { + firmware_end_addr = riscv_load_firmware(firmware_name, + memmap[SPIKE_DRAM].base, + htif_symbol_callback); + g_free(firmware_name); + } /* Load kernel */ if (machine->kernel_filename) { @@ -279,7 +319,7 @@ static void spike_board_init(MachineState *machine) /* Create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc[0])); + riscv_is_32bit(&s->soc[0]), htif_custom_base); /* Load initrd */ if (machine->kernel_filename && machine->initrd_filename) { @@ -307,7 +347,8 @@ static void spike_board_init(MachineState *machine) fdt_load_addr); /* initialize HTIF using symbols found in load_kernel */ - htif_mm_init(system_memory, serial_hd(0), memmap[SPIKE_HTIF].base); + htif_mm_init(system_memory, serial_hd(0), memmap[SPIKE_HTIF].base, + htif_custom_base); } static void spike_machine_instance_init(Object *obj) diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index 9e8ebbe017..5958c5b986 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -44,11 +44,8 @@ typedef struct HTIFState { void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, uint64_t st_size); -/* Check if HTIF uses ELF symbols */ -bool htif_uses_elf_symbols(void); - /* legacy pre qom */ HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr, - uint64_t nonelf_base); + uint64_t nonelf_base, bool custom_base); #endif From 44e7372b213bad4e4589d765f011b25c897c8ab1 Mon Sep 17 00:00:00 2001 From: Dongxue Zhang Date: Thu, 15 Dec 2022 16:27:14 +0800 Subject: [PATCH 137/814] target/riscv/cpu.c: Fix elen check The elen check should be cpu->cfg.elen in range [8, 64]. Signed-off-by: Dongxue Zhang Reviewed-by: LIU Zhiwei Reviewed-by: Frank Chang Reviewed-by: Alistair Francis Message-Id: <167236721596.15277.2653405273227256289-0@git.sr.ht> [ Changes by AF: - Tidy up commit message ] Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..a2e6238bd7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -882,7 +882,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) "Vector extension ELEN must be power of 2"); return; } - if (cpu->cfg.elen > 64 || cpu->cfg.vlen < 8) { + if (cpu->cfg.elen > 64 || cpu->cfg.elen < 8) { error_setg(errp, "Vector extension implementation only supports ELEN " "in the range [8, 64]"); From db2b9a59ca633602c4a18474a104182920858060 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:31 -0300 Subject: [PATCH 138/814] tests/avocado: add RISC-V OpenSBI boot test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test is used to do a quick sanity check to ensure that we're able to run the existing QEMU FW image. 'sifive_u', 'spike' and 'virt' riscv64 machines, and 'sifive_u' and 'virt' 32 bit machines are able to run the default RISCV64_BIOS_BIN | RISCV32_BIOS_BIN firmware with minimal options. The riscv32 'spike' machine isn't bootable at this moment, requiring an OpenSBI fix [1] and QEMU side changes [2]. We could just leave at that or add a 'skip' test to remind us about it. To work as a reminder that we have a riscv32 'spike' test that should be enabled as soon as OpenSBI QEMU rom receives the fix, we're adding a 'skip' test: (06/18) tests/avocado/riscv_opensbi.py:RiscvOpenSBI.test_riscv32_spike: SKIP: requires OpenSBI fix to work [1] https://patchwork.ozlabs.org/project/opensbi/patch/20221226033603.1860569-1-bmeng@tinylab.org/ [2] https://patchwork.ozlabs.org/project/qemu-devel/list/?series=334159 Cc: Cleber Rosa Cc: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Tested-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-Id: <20230102115241.25733-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- tests/avocado/riscv_opensbi.py | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tests/avocado/riscv_opensbi.py diff --git a/tests/avocado/riscv_opensbi.py b/tests/avocado/riscv_opensbi.py new file mode 100644 index 0000000000..e02f0d404a --- /dev/null +++ b/tests/avocado/riscv_opensbi.py @@ -0,0 +1,65 @@ +# OpenSBI boot test for RISC-V machines +# +# Copyright (c) 2022, Ventana Micro +# +# 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 avocado_qemu import QemuSystemTest +from avocado import skip +from avocado_qemu import wait_for_console_pattern + +class RiscvOpenSBI(QemuSystemTest): + """ + :avocado: tags=accel:tcg + """ + timeout = 5 + + def boot_opensbi(self): + self.vm.set_console() + self.vm.launch() + wait_for_console_pattern(self, 'Platform Name') + wait_for_console_pattern(self, 'Boot HART MEDELEG') + + @skip("requires OpenSBI fix to work") + def test_riscv32_spike(self): + """ + :avocado: tags=arch:riscv32 + :avocado: tags=machine:spike + """ + self.boot_opensbi() + + def test_riscv64_spike(self): + """ + :avocado: tags=arch:riscv64 + :avocado: tags=machine:spike + """ + self.boot_opensbi() + + def test_riscv32_sifive_u(self): + """ + :avocado: tags=arch:riscv32 + :avocado: tags=machine:sifive_u + """ + self.boot_opensbi() + + def test_riscv64_sifive_u(self): + """ + :avocado: tags=arch:riscv64 + :avocado: tags=machine:sifive_u + """ + self.boot_opensbi() + + def test_riscv32_virt(self): + """ + :avocado: tags=arch:riscv32 + :avocado: tags=machine:virt + """ + self.boot_opensbi() + + def test_riscv64_virt(self): + """ + :avocado: tags=arch:riscv64 + :avocado: tags=machine:virt + """ + self.boot_opensbi() From 3139929da4da015f372c11f9e9e1f2538f9767ed Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:32 -0300 Subject: [PATCH 139/814] hw/riscv/spike: use 'fdt' from MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineState object provides a 'fdt' pointer that is already being used by other RISC-V machines, and it's also used by the 'dumpdtb' QMP command. Remove the 'fdt' pointer from SpikeState and use MachineState::fdt instead. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20230102115241.25733-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 12 +++++------- include/hw/riscv/spike.h | 2 -- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 1679c325d5..25c5420ee6 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -53,6 +53,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, bool is_32_bit, bool htif_custom_base) { void *fdt; + int fdt_size; uint64_t addr, size; unsigned long clint_addr; int cpu, socket; @@ -65,7 +66,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, "sifive,clint0", "riscv,clint0" }; - fdt = s->fdt = create_device_tree(&s->fdt_size); + fdt = mc->fdt = create_device_tree(&fdt_size); if (!fdt) { error_report("create_device_tree() failed"); exit(1); @@ -327,18 +328,15 @@ static void spike_board_init(MachineState *machine) hwaddr end = riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, &start); - qemu_fdt_setprop_cell(s->fdt, "/chosen", + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-start", start); - qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", end); } /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, - machine->ram_size, s->fdt); - - /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ - machine->fdt = s->fdt; + machine->ram_size, machine->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h index 73bf2a9aad..0c2a223763 100644 --- a/include/hw/riscv/spike.h +++ b/include/hw/riscv/spike.h @@ -37,8 +37,6 @@ struct SpikeState { /*< public >*/ RISCVHartArrayState soc[SPIKE_SOCKETS_MAX]; - void *fdt; - int fdt_size; }; enum { From 60c7dfa2a3d7eb3919054367c2d03d4fc1bef3f1 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:33 -0300 Subject: [PATCH 140/814] hw/riscv/sifive_u: use 'fdt' from MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineState object provides a 'fdt' pointer that is already being used by other RISC-V machines, and it's also used by the 'dumpdtb' QMP command. Remove the 'fdt' pointer from SiFiveUState and use MachineState::fdt instead. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20230102115241.25733-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 15 ++++++--------- include/hw/riscv/sifive_u.h | 3 --- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index a58ddb36ac..ddceb750ea 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -98,7 +98,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, { MachineState *ms = MACHINE(qdev_get_machine()); void *fdt; - int cpu; + int cpu, fdt_size; uint32_t *cells; char *nodename; uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1; @@ -112,14 +112,14 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, }; if (ms->dtb) { - fdt = s->fdt = load_device_tree(ms->dtb, &s->fdt_size); + fdt = ms->fdt = load_device_tree(ms->dtb, &fdt_size); if (!fdt) { error_report("load_device_tree() failed"); exit(1); } goto update_bootargs; } else { - fdt = s->fdt = create_device_tree(&s->fdt_size); + fdt = ms->fdt = create_device_tree(&fdt_size); if (!fdt) { error_report("create_device_tree() failed"); exit(1); @@ -612,9 +612,9 @@ static void sifive_u_machine_init(MachineState *machine) hwaddr end = riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, &start); - qemu_fdt_setprop_cell(s->fdt, "/chosen", + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-start", start); - qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", end); } } else { @@ -627,14 +627,11 @@ static void sifive_u_machine_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DEV_DRAM].base, - machine->ram_size, s->fdt); + machine->ram_size, machine->fdt); if (!riscv_is_32bit(&s->soc.u_cpus)) { start_addr_hi32 = (uint64_t)start_addr >> 32; } - /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ - machine->fdt = s->fdt; - /* reset vector */ uint32_t reset_vec[12] = { s->msel, /* MSEL pin state */ diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index a67328f7ad..65af306963 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -69,9 +69,6 @@ typedef struct SiFiveUState { /*< public >*/ SiFiveUSoCState soc; - void *fdt; - int fdt_size; - bool start_in_flash; uint32_t msel; uint32_t serial; From 1db0c57adeb981c9581f7729e8e8dfb60bdb4e7c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:34 -0300 Subject: [PATCH 141/814] hw/riscv/boot.c: exit early if filename is NULL in load functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit riscv_load_firmware(), riscv_load_initrd() and riscv_load_kernel() works under the assumption that a 'filename' parameter is always not NULL. This is currently the case since all callers of these functions are checking for NULL before calling them. Add an g_assert() to make sure that a NULL value in these cases are to be considered a bug. Suggested-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel Henrique Barboza Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20230102115241.25733-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 98b80af51b..31aa3385a0 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -153,6 +153,8 @@ target_ulong riscv_load_firmware(const char *firmware_filename, uint64_t firmware_entry, firmware_end; ssize_t firmware_size; + g_assert(firmware_filename != NULL); + if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, &firmware_entry, NULL, &firmware_end, NULL, 0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { @@ -177,6 +179,8 @@ target_ulong riscv_load_kernel(const char *kernel_filename, { uint64_t kernel_load_base, kernel_entry; + g_assert(kernel_filename != NULL); + /* * NB: Use low address not ELF entry point to ensure that the fw_dynamic * behaviour when loading an ELF matches the fw_payload, fw_jump and BBL @@ -209,6 +213,8 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, { ssize_t size; + g_assert(filename != NULL); + /* * We want to put the initrd far enough into RAM that when the * kernel is uncompressed it will not clobber the initrd. However From c44df400d9fc23d1d135f6aa723cb58ada858ee3 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:35 -0300 Subject: [PATCH 142/814] hw/riscv/spike.c: load initrd right after riscv_load_kernel() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make the code more in line with what the other boards are doing. We'll also avoid an extra check to machine->kernel_filename since we already checked that before executing riscv_load_kernel(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20230102115241.25733-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 25c5420ee6..004dfb2d5b 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -302,6 +302,10 @@ static void spike_board_init(MachineState *machine) g_free(firmware_name); } + /* Create device tree */ + create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, + riscv_is_32bit(&s->soc[0]), htif_custom_base); + /* Load kernel */ if (machine->kernel_filename) { kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], @@ -310,6 +314,17 @@ static void spike_board_init(MachineState *machine) kernel_entry = riscv_load_kernel(machine->kernel_filename, kernel_start_addr, htif_symbol_callback); + + if (machine->initrd_filename) { + hwaddr start; + hwaddr end = riscv_load_initrd(machine->initrd_filename, + machine->ram_size, kernel_entry, + &start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", + end); + } } else { /* * If dynamic firmware is used, it doesn't know where is the next mode @@ -318,22 +333,6 @@ static void spike_board_init(MachineState *machine) kernel_entry = 0; } - /* Create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc[0]), htif_custom_base); - - /* Load initrd */ - if (machine->kernel_filename && machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", - end); - } - /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, machine->ram_size, machine->fdt); From b9a65476cbfc7a47a5c06ffdd58922fd295c5027 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:36 -0300 Subject: [PATCH 143/814] hw/riscv: write initrd 'chosen' FDT inside riscv_load_initrd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit riscv_load_initrd() returns the initrd end addr while also writing a 'start' var to mark the addr start. These informations are being used just to write the initrd FDT node. Every existing caller of riscv_load_initrd() is writing the FDT in the same manner. We can simplify things by writing the FDT inside riscv_load_initrd(), sparing callers from having to manage start/end addrs to write the FDT themselves. An 'if (fdt)' check is already inserted at the end of the function because we'll end up using it later on with other boards that doesn´t have a FDT. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230102115241.25733-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 18 ++++++++++++------ hw/riscv/microchip_pfsoc.c | 10 ++-------- hw/riscv/sifive_u.c | 10 ++-------- hw/riscv/spike.c | 10 ++-------- hw/riscv/virt.c | 10 ++-------- include/hw/riscv/boot.h | 4 ++-- 6 files changed, 22 insertions(+), 40 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 31aa3385a0..6b948d1c9e 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -208,9 +208,10 @@ target_ulong riscv_load_kernel(const char *kernel_filename, exit(1); } -hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, - uint64_t kernel_entry, hwaddr *start) +void riscv_load_initrd(const char *filename, uint64_t mem_size, + uint64_t kernel_entry, void *fdt) { + hwaddr start, end; ssize_t size; g_assert(filename != NULL); @@ -226,18 +227,23 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, * halfway into RAM, and for boards with 256MB of RAM or more we put * the initrd at 128MB. */ - *start = kernel_entry + MIN(mem_size / 2, 128 * MiB); + start = kernel_entry + MIN(mem_size / 2, 128 * MiB); - size = load_ramdisk(filename, *start, mem_size - *start); + size = load_ramdisk(filename, start, mem_size - start); if (size == -1) { - size = load_image_targphys(filename, *start, mem_size - *start); + size = load_image_targphys(filename, start, mem_size - start); if (size == -1) { error_report("could not load ramdisk '%s'", filename); exit(1); } } - return *start + size; + /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */ + if (fdt) { + end = start + size; + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start); + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", end); + } } uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index b10321b564..593a799549 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -633,14 +633,8 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) kernel_start_addr, NULL); if (machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-end", end); + riscv_load_initrd(machine->initrd_filename, machine->ram_size, + kernel_entry, machine->fdt); } if (machine->kernel_cmdline && *machine->kernel_cmdline) { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index ddceb750ea..37f5087172 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -608,14 +608,8 @@ static void sifive_u_machine_init(MachineState *machine) kernel_start_addr, NULL); if (machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", - end); + riscv_load_initrd(machine->initrd_filename, machine->ram_size, + kernel_entry, machine->fdt); } } else { /* diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 004dfb2d5b..5668fe0694 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -316,14 +316,8 @@ static void spike_board_init(MachineState *machine) htif_symbol_callback); if (machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", - end); + riscv_load_initrd(machine->initrd_filename, machine->ram_size, + kernel_entry, machine->fdt); } } else { /* diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 408f7a2256..5967b136b4 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1291,14 +1291,8 @@ static void virt_machine_done(Notifier *notifier, void *data) kernel_start_addr, NULL); if (machine->initrd_filename) { - hwaddr start; - hwaddr end = riscv_load_initrd(machine->initrd_filename, - machine->ram_size, kernel_entry, - &start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", - end); + riscv_load_initrd(machine->initrd_filename, machine->ram_size, + kernel_entry, machine->fdt); } } else { /* diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index b273ab22f7..e37e1d1238 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -46,8 +46,8 @@ target_ulong riscv_load_firmware(const char *firmware_filename, target_ulong riscv_load_kernel(const char *kernel_filename, target_ulong firmware_end_addr, symbol_fn_t sym_cb); -hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, - uint64_t kernel_entry, hwaddr *start); +void riscv_load_initrd(const char *filename, uint64_t mem_size, + uint64_t kernel_entry, void *fdt); uint64_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, From b1f19f238cae53b5c90085db45e0335af19f5387 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:37 -0300 Subject: [PATCH 144/814] hw/riscv: write bootargs 'chosen' FDT after riscv_load_kernel() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sifive_u, spike and virt machines are writing the 'bootargs' FDT node during their respective create_fdt(). Given that bootargs is written only when '-append' is used, and this option is only allowed with the '-kernel' option, which in turn is already being check before executing riscv_load_kernel(), write 'bootargs' in the same code path as riscv_load_kernel(). Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230102115241.25733-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 11 +++++------ hw/riscv/spike.c | 9 +++++---- hw/riscv/virt.c | 11 +++++------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 37f5087172..3e6df87b5b 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -117,7 +117,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, error_report("load_device_tree() failed"); exit(1); } - goto update_bootargs; } else { fdt = ms->fdt = create_device_tree(&fdt_size); if (!fdt) { @@ -510,11 +509,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename); g_free(nodename); - -update_bootargs: - if (cmdline && *cmdline) { - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); - } } static void sifive_u_machine_reset(void *opaque, int n, int level) @@ -611,6 +605,11 @@ static void sifive_u_machine_init(MachineState *machine) riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, machine->fdt); } + + if (machine->kernel_cmdline && *machine->kernel_cmdline) { + qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs", + machine->kernel_cmdline); + } } else { /* * If dynamic firmware is used, it doesn't know where is the next mode diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 5668fe0694..60e2912be5 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -179,10 +179,6 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif"); - - if (cmdline && *cmdline) { - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); - } } static bool spike_test_elf_image(char *filename) @@ -319,6 +315,11 @@ static void spike_board_init(MachineState *machine) riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, machine->fdt); } + + if (machine->kernel_cmdline && *machine->kernel_cmdline) { + qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs", + machine->kernel_cmdline); + } } else { /* * If dynamic firmware is used, it doesn't know where is the next mode diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 5967b136b4..6c946b6def 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1012,7 +1012,6 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, error_report("load_device_tree() failed"); exit(1); } - goto update_bootargs; } else { mc->fdt = create_device_tree(&s->fdt_size); if (!mc->fdt) { @@ -1050,11 +1049,6 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_fw_cfg(s, memmap); create_fdt_pmu(s); -update_bootargs: - if (cmdline && *cmdline) { - qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline); - } - /* Pass seed to RNG */ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); @@ -1294,6 +1288,11 @@ static void virt_machine_done(Notifier *notifier, void *data) riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, machine->fdt); } + + if (machine->kernel_cmdline && *machine->kernel_cmdline) { + qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs", + machine->kernel_cmdline); + } } else { /* * If dynamic firmware is used, it doesn't know where is the next mode From 1f99146103dc49aabfa832f8527804087a4c2651 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:38 -0300 Subject: [PATCH 145/814] hw/riscv/boot.c: use MachineState in riscv_load_initrd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'filename', 'mem_size' and 'fdt' from riscv_load_initrd() can all be retrieved by the MachineState object for all callers. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20230102115241.25733-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 6 ++++-- hw/riscv/microchip_pfsoc.c | 3 +-- hw/riscv/sifive_u.c | 3 +-- hw/riscv/spike.c | 3 +-- hw/riscv/virt.c | 3 +-- include/hw/riscv/boot.h | 3 +-- 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 6b948d1c9e..d3e780c3b6 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -208,9 +208,11 @@ target_ulong riscv_load_kernel(const char *kernel_filename, exit(1); } -void riscv_load_initrd(const char *filename, uint64_t mem_size, - uint64_t kernel_entry, void *fdt) +void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) { + const char *filename = machine->initrd_filename; + uint64_t mem_size = machine->ram_size; + void *fdt = machine->fdt; hwaddr start, end; ssize_t size; diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 593a799549..1e9b0a420e 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -633,8 +633,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) kernel_start_addr, NULL); if (machine->initrd_filename) { - riscv_load_initrd(machine->initrd_filename, machine->ram_size, - kernel_entry, machine->fdt); + riscv_load_initrd(machine, kernel_entry); } if (machine->kernel_cmdline && *machine->kernel_cmdline) { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 3e6df87b5b..c40885ed5c 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -602,8 +602,7 @@ static void sifive_u_machine_init(MachineState *machine) kernel_start_addr, NULL); if (machine->initrd_filename) { - riscv_load_initrd(machine->initrd_filename, machine->ram_size, - kernel_entry, machine->fdt); + riscv_load_initrd(machine, kernel_entry); } if (machine->kernel_cmdline && *machine->kernel_cmdline) { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 60e2912be5..99dec74fe8 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -312,8 +312,7 @@ static void spike_board_init(MachineState *machine) htif_symbol_callback); if (machine->initrd_filename) { - riscv_load_initrd(machine->initrd_filename, machine->ram_size, - kernel_entry, machine->fdt); + riscv_load_initrd(machine, kernel_entry); } if (machine->kernel_cmdline && *machine->kernel_cmdline) { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 6c946b6def..02f1369843 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1285,8 +1285,7 @@ static void virt_machine_done(Notifier *notifier, void *data) kernel_start_addr, NULL); if (machine->initrd_filename) { - riscv_load_initrd(machine->initrd_filename, machine->ram_size, - kernel_entry, machine->fdt); + riscv_load_initrd(machine, kernel_entry); } if (machine->kernel_cmdline && *machine->kernel_cmdline) { diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index e37e1d1238..cfd72ecabf 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -46,8 +46,7 @@ target_ulong riscv_load_firmware(const char *firmware_filename, target_ulong riscv_load_kernel(const char *kernel_filename, target_ulong firmware_end_addr, symbol_fn_t sym_cb); -void riscv_load_initrd(const char *filename, uint64_t mem_size, - uint64_t kernel_entry, void *fdt); +void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry); uint64_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, From 60c1f05e365e08cbdc6a9a64e29a109903a32ee6 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 2 Jan 2023 08:52:39 -0300 Subject: [PATCH 146/814] hw/riscv/boot.c: use MachineState in riscv_load_kernel() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers are using kernel_filename as machine->kernel_filename. This will also simplify the changes in riscv_load_kernel() that we're going to do next. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20230102115241.25733-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 3 ++- hw/riscv/microchip_pfsoc.c | 3 +-- hw/riscv/opentitan.c | 3 +-- hw/riscv/sifive_e.c | 3 +-- hw/riscv/sifive_u.c | 3 +-- hw/riscv/spike.c | 3 +-- hw/riscv/virt.c | 3 +-- include/hw/riscv/boot.h | 2 +- 8 files changed, 9 insertions(+), 14 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index d3e780c3b6..2594276223 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -173,10 +173,11 @@ target_ulong riscv_load_firmware(const char *firmware_filename, exit(1); } -target_ulong riscv_load_kernel(const char *kernel_filename, +target_ulong riscv_load_kernel(MachineState *machine, target_ulong kernel_start_addr, symbol_fn_t sym_cb) { + const char *kernel_filename = machine->kernel_filename; uint64_t kernel_load_base, kernel_entry; g_assert(kernel_filename != NULL); diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 1e9b0a420e..82ae5e7023 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -629,8 +629,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, firmware_end_addr); - kernel_entry = riscv_load_kernel(machine->kernel_filename, - kernel_start_addr, NULL); + kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL); if (machine->initrd_filename) { riscv_load_initrd(machine, kernel_entry); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 85ffdac5be..64d5d435b9 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -101,8 +101,7 @@ static void opentitan_board_init(MachineState *machine) } if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, - memmap[IBEX_DEV_RAM].base, NULL); + riscv_load_kernel(machine, memmap[IBEX_DEV_RAM].base, NULL); } } diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index d65d2fd869..3e3f4b0088 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -114,8 +114,7 @@ static void sifive_e_machine_init(MachineState *machine) memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory); if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, - memmap[SIFIVE_E_DEV_DTIM].base, NULL); + riscv_load_kernel(machine, memmap[SIFIVE_E_DEV_DTIM].base, NULL); } } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index c40885ed5c..bac394c959 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -598,8 +598,7 @@ static void sifive_u_machine_init(MachineState *machine) kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, firmware_end_addr); - kernel_entry = riscv_load_kernel(machine->kernel_filename, - kernel_start_addr, NULL); + kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL); if (machine->initrd_filename) { riscv_load_initrd(machine, kernel_entry); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 99dec74fe8..bff9475686 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -307,8 +307,7 @@ static void spike_board_init(MachineState *machine) kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], firmware_end_addr); - kernel_entry = riscv_load_kernel(machine->kernel_filename, - kernel_start_addr, + kernel_entry = riscv_load_kernel(machine, kernel_start_addr, htif_symbol_callback); if (machine->initrd_filename) { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 02f1369843..c8e35f861e 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1281,8 +1281,7 @@ static void virt_machine_done(Notifier *notifier, void *data) kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], firmware_end_addr); - kernel_entry = riscv_load_kernel(machine->kernel_filename, - kernel_start_addr, NULL); + kernel_entry = riscv_load_kernel(machine, kernel_start_addr, NULL); if (machine->initrd_filename) { riscv_load_initrd(machine, kernel_entry); diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index cfd72ecabf..f94653a09b 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -43,7 +43,7 @@ char *riscv_find_firmware(const char *firmware_filename, target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb); -target_ulong riscv_load_kernel(const char *kernel_filename, +target_ulong riscv_load_kernel(MachineState *machine, target_ulong firmware_end_addr, symbol_fn_t sym_cb); void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry); From c66ffcd5358ba88e93e1ffb15ae42ca52dab12a8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 13 Jan 2023 14:52:29 -0300 Subject: [PATCH 147/814] target/riscv/cpu: set cpu->cfg in register_cpu_props() There is an informal contract between the cpu_init() functions and riscv_cpu_realize(): if cpu->env.misa_ext is zero, assume that the default settings were loaded via register_cpu_props() and do validations to set env.misa_ext. If it's not zero, skip this whole process and assume that the board somehow did everything. At this moment, all SiFive CPUs are setting a non-zero misa_ext during their cpu_init() and skipping a good chunk of riscv_cpu_realize(). This causes problems when the code being skipped in riscv_cpu_realize() contains fixes or assumptions that affects all CPUs, meaning that SiFive CPUs are missing out. To allow this code to not be skipped anymore, all the cpu->cfg.ext_* attributes needs to be set during cpu_init() time. At this moment this is being done in register_cpu_props(). The SiFive boards are setting their own extensions during cpu_init() though, meaning that they don't want all the defaults from register_cpu_props(). Let's move the contract between *_cpu_init() and riscv_cpu_realize() to register_cpu_props(). Inside this function we'll check if cpu->env.misa_ext was set and, if that's the case, set all relevant cpu->cfg.ext_* attributes, and only that. Leave the 'misa_ext' = 0 case as is today, i.e. loading all the defaults from riscv_cpu_extensions[]. register_cpu_props() can then be called by all the cpu_init() functions, including the SiFive ones. This will make all CPUs behave more in line with what riscv_cpu_realize() expects. This will also make the cpu_init() functions even more alike, but at this moment we would need some design changes in how we're initializing extensions/attributes (e.g. some CPUs are setting cfg options after register_cpu_props(), so we can't simply add the function to a common post_init() hook) to make a common cpu_init() code across all CPUs. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20230113175230.473975-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 40 ++++++++++++++++++++++++++++++++++++++++ target/riscv/cpu.h | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a2e6238bd7..e682102c2a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -256,6 +256,7 @@ static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_10_0); } @@ -265,6 +266,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -299,6 +301,7 @@ static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_10_0); } @@ -308,6 +311,7 @@ static void rv32_sifive_e_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -318,6 +322,7 @@ static void rv32_ibex_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_11_0); cpu->cfg.mmu = false; cpu->cfg.epmp = true; @@ -329,6 +334,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); + register_cpu_props(DEVICE(obj)); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -1083,10 +1089,44 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; +/* + * Register CPU props based on env.misa_ext. If a non-zero + * value was set, register only the required cpu->cfg.ext_* + * properties and leave. env.misa_ext = 0 means that we want + * all the default properties to be registered. + */ static void register_cpu_props(DeviceState *dev) { + RISCVCPU *cpu = RISCV_CPU(OBJECT(dev)); + uint32_t misa_ext = cpu->env.misa_ext; Property *prop; + /* + * If misa_ext is not zero, set cfg properties now to + * allow them to be read during riscv_cpu_realize() + * later on. + */ + if (cpu->env.misa_ext != 0) { + cpu->cfg.ext_i = misa_ext & RVI; + cpu->cfg.ext_e = misa_ext & RVE; + cpu->cfg.ext_m = misa_ext & RVM; + cpu->cfg.ext_a = misa_ext & RVA; + cpu->cfg.ext_f = misa_ext & RVF; + cpu->cfg.ext_d = misa_ext & RVD; + cpu->cfg.ext_v = misa_ext & RVV; + cpu->cfg.ext_c = misa_ext & RVC; + cpu->cfg.ext_s = misa_ext & RVS; + cpu->cfg.ext_u = misa_ext & RVU; + cpu->cfg.ext_h = misa_ext & RVH; + cpu->cfg.ext_j = misa_ext & RVJ; + + /* + * We don't want to set the default riscv_cpu_extensions + * in this case. + */ + return; + } + for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 61a9a40958..bcf0826753 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -63,6 +63,10 @@ #define RV(x) ((target_ulong)1 << (x - 'A')) +/* + * Consider updating register_cpu_props() when adding + * new MISA bits here. + */ #define RVI RV('I') #define RVE RV('E') /* E and I are mutually exclusive */ #define RVM RV('M') From 5ab1095213318effd9bb4667f7f52da21f81acc6 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 13 Jan 2023 14:52:30 -0300 Subject: [PATCH 148/814] target/riscv/cpu.c: do not skip misa logic in riscv_cpu_realize() All RISCV CPUs are setting cpu->cfg during their cpu_init() functions, meaning that there's no reason to skip all the misa validation and setup if misa_ext was set beforehand - especially since we're setting an updated value in set_misa() in the end. Put this code chunk into a new riscv_cpu_validate_set_extensions() helper and always execute it regardless of what the board set in env->misa_ext. This will put more responsibility in how each board is going to init their attributes and extensions if they're not using the defaults. It'll also allow realize() to do its job looking only at the extensions enabled per se, not corner cases that some CPUs might have, and we won't have to change multiple code paths to fix or change how extensions work. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Message-Id: <20230113175230.473975-3-dbarboza@ventanamicro.com> [ Changes by AF: - Rebase ] Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 399 +++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 194 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e682102c2a..c192d96a94 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -625,6 +625,207 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +/* + * Check consistency between chosen extensions while setting + * cpu->cfg accordingly, doing a set_misa() in the end. + */ +static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) +{ + CPURISCVState *env = &cpu->env; + uint32_t ext = 0; + + /* Do some ISA extension error checking */ + if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && + cpu->cfg.ext_a && cpu->cfg.ext_f && + cpu->cfg.ext_d && + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); + cpu->cfg.ext_i = true; + cpu->cfg.ext_m = true; + cpu->cfg.ext_a = true; + cpu->cfg.ext_f = true; + cpu->cfg.ext_d = true; + cpu->cfg.ext_icsr = true; + cpu->cfg.ext_ifencei = true; + } + + if (cpu->cfg.ext_i && cpu->cfg.ext_e) { + error_setg(errp, + "I and E extensions are incompatible"); + return; + } + + if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { + error_setg(errp, + "Either I or E extension must be set"); + return; + } + + if (cpu->cfg.ext_s && !cpu->cfg.ext_u) { + error_setg(errp, + "Setting S extension without U extension is illegal"); + return; + } + + if (cpu->cfg.ext_h && !cpu->cfg.ext_i) { + error_setg(errp, + "H depends on an I base integer ISA with 32 x registers"); + return; + } + + if (cpu->cfg.ext_h && !cpu->cfg.ext_s) { + error_setg(errp, "H extension implicitly requires S-mode"); + return; + } + + if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) { + error_setg(errp, "F extension requires Zicsr"); + return; + } + + if ((cpu->cfg.ext_zawrs) && !cpu->cfg.ext_a) { + error_setg(errp, "Zawrs extension requires A extension"); + return; + } + + if ((cpu->cfg.ext_zfh || cpu->cfg.ext_zfhmin) && !cpu->cfg.ext_f) { + error_setg(errp, "Zfh/Zfhmin extensions require F extension"); + return; + } + + if (cpu->cfg.ext_d && !cpu->cfg.ext_f) { + error_setg(errp, "D extension requires F extension"); + return; + } + + if (cpu->cfg.ext_v && !cpu->cfg.ext_d) { + error_setg(errp, "V extension requires D extension"); + return; + } + + if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); + return; + } + + /* Set the ISA extensions, checks should have happened above */ + if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || + cpu->cfg.ext_zhinxmin) { + cpu->cfg.ext_zfinx = true; + } + + if (cpu->cfg.ext_zfinx) { + if (!cpu->cfg.ext_icsr) { + error_setg(errp, "Zfinx extension requires Zicsr"); + return; + } + if (cpu->cfg.ext_f) { + error_setg(errp, + "Zfinx cannot be supported together with F extension"); + return; + } + } + + if (cpu->cfg.ext_zk) { + cpu->cfg.ext_zkn = true; + cpu->cfg.ext_zkr = true; + cpu->cfg.ext_zkt = true; + } + + if (cpu->cfg.ext_zkn) { + cpu->cfg.ext_zbkb = true; + cpu->cfg.ext_zbkc = true; + cpu->cfg.ext_zbkx = true; + cpu->cfg.ext_zkne = true; + cpu->cfg.ext_zknd = true; + cpu->cfg.ext_zknh = true; + } + + if (cpu->cfg.ext_zks) { + cpu->cfg.ext_zbkb = true; + cpu->cfg.ext_zbkc = true; + cpu->cfg.ext_zbkx = true; + cpu->cfg.ext_zksed = true; + cpu->cfg.ext_zksh = true; + } + + if (cpu->cfg.ext_i) { + ext |= RVI; + } + if (cpu->cfg.ext_e) { + ext |= RVE; + } + if (cpu->cfg.ext_m) { + ext |= RVM; + } + if (cpu->cfg.ext_a) { + ext |= RVA; + } + if (cpu->cfg.ext_f) { + ext |= RVF; + } + if (cpu->cfg.ext_d) { + ext |= RVD; + } + if (cpu->cfg.ext_c) { + ext |= RVC; + } + if (cpu->cfg.ext_s) { + ext |= RVS; + } + if (cpu->cfg.ext_u) { + ext |= RVU; + } + if (cpu->cfg.ext_h) { + ext |= RVH; + } + if (cpu->cfg.ext_v) { + int vext_version = VEXT_VERSION_1_00_0; + ext |= RVV; + if (!is_power_of_2(cpu->cfg.vlen)) { + error_setg(errp, + "Vector extension VLEN must be power of 2"); + return; + } + if (cpu->cfg.vlen > RV_VLEN_MAX || cpu->cfg.vlen < 128) { + error_setg(errp, + "Vector extension implementation only supports VLEN " + "in the range [128, %d]", RV_VLEN_MAX); + return; + } + if (!is_power_of_2(cpu->cfg.elen)) { + error_setg(errp, + "Vector extension ELEN must be power of 2"); + return; + } + if (cpu->cfg.elen > 64 || cpu->cfg.elen < 8) { + error_setg(errp, + "Vector extension implementation only supports ELEN " + "in the range [8, 64]"); + return; + } + if (cpu->cfg.vext_spec) { + if (!g_strcmp0(cpu->cfg.vext_spec, "v1.0")) { + vext_version = VEXT_VERSION_1_00_0; + } else { + error_setg(errp, + "Unsupported vector spec version '%s'", + cpu->cfg.vext_spec); + return; + } + } else { + qemu_log("vector version is not specified, " + "use the default value v1.0\n"); + } + set_vext_version(env, vext_version); + } + if (cpu->cfg.ext_j) { + ext |= RVJ; + } + + set_misa(env, env->misa_mxl, ext); +} + static void riscv_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -720,200 +921,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } assert(env->misa_mxl_max == env->misa_mxl); - /* If only MISA_EXT is unset for misa, then set it from properties */ - if (env->misa_ext == 0) { - uint32_t ext = 0; - - /* Do some ISA extension error checking */ - if (cpu->cfg.ext_g && !(cpu->cfg.ext_i && cpu->cfg.ext_m && - cpu->cfg.ext_a && cpu->cfg.ext_f && - cpu->cfg.ext_d && - cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) { - warn_report("Setting G will also set IMAFD_Zicsr_Zifencei"); - cpu->cfg.ext_i = true; - cpu->cfg.ext_m = true; - cpu->cfg.ext_a = true; - cpu->cfg.ext_f = true; - cpu->cfg.ext_d = true; - cpu->cfg.ext_icsr = true; - cpu->cfg.ext_ifencei = true; - } - - if (cpu->cfg.ext_i && cpu->cfg.ext_e) { - error_setg(errp, - "I and E extensions are incompatible"); - return; - } - - if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { - error_setg(errp, - "Either I or E extension must be set"); - return; - } - - if (cpu->cfg.ext_s && !cpu->cfg.ext_u) { - error_setg(errp, - "Setting S extension without U extension is illegal"); - return; - } - - if (cpu->cfg.ext_h && !cpu->cfg.ext_i) { - error_setg(errp, - "H depends on an I base integer ISA with 32 x registers"); - return; - } - - if (cpu->cfg.ext_h && !cpu->cfg.ext_s) { - error_setg(errp, "H extension implicitly requires S-mode"); - return; - } - - if (cpu->cfg.ext_f && !cpu->cfg.ext_icsr) { - error_setg(errp, "F extension requires Zicsr"); - return; - } - - if ((cpu->cfg.ext_zawrs) && !cpu->cfg.ext_a) { - error_setg(errp, "Zawrs extension requires A extension"); - return; - } - - if ((cpu->cfg.ext_zfh || cpu->cfg.ext_zfhmin) && !cpu->cfg.ext_f) { - error_setg(errp, "Zfh/Zfhmin extensions require F extension"); - return; - } - - if (cpu->cfg.ext_d && !cpu->cfg.ext_f) { - error_setg(errp, "D extension requires F extension"); - return; - } - - if (cpu->cfg.ext_v && !cpu->cfg.ext_d) { - error_setg(errp, "V extension requires D extension"); - return; - } - - if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { - error_setg(errp, "Zve32f/Zve64f extensions require F extension"); - return; - } - - /* Set the ISA extensions, checks should have happened above */ - if (cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx || - cpu->cfg.ext_zhinxmin) { - cpu->cfg.ext_zfinx = true; - } - - if (cpu->cfg.ext_zfinx) { - if (!cpu->cfg.ext_icsr) { - error_setg(errp, "Zfinx extension requires Zicsr"); - return; - } - if (cpu->cfg.ext_f) { - error_setg(errp, - "Zfinx cannot be supported together with F extension"); - return; - } - } - - if (cpu->cfg.ext_zk) { - cpu->cfg.ext_zkn = true; - cpu->cfg.ext_zkr = true; - cpu->cfg.ext_zkt = true; - } - - if (cpu->cfg.ext_zkn) { - cpu->cfg.ext_zbkb = true; - cpu->cfg.ext_zbkc = true; - cpu->cfg.ext_zbkx = true; - cpu->cfg.ext_zkne = true; - cpu->cfg.ext_zknd = true; - cpu->cfg.ext_zknh = true; - } - - if (cpu->cfg.ext_zks) { - cpu->cfg.ext_zbkb = true; - cpu->cfg.ext_zbkc = true; - cpu->cfg.ext_zbkx = true; - cpu->cfg.ext_zksed = true; - cpu->cfg.ext_zksh = true; - } - - if (cpu->cfg.ext_i) { - ext |= RVI; - } - if (cpu->cfg.ext_e) { - ext |= RVE; - } - if (cpu->cfg.ext_m) { - ext |= RVM; - } - if (cpu->cfg.ext_a) { - ext |= RVA; - } - if (cpu->cfg.ext_f) { - ext |= RVF; - } - if (cpu->cfg.ext_d) { - ext |= RVD; - } - if (cpu->cfg.ext_c) { - ext |= RVC; - } - if (cpu->cfg.ext_s) { - ext |= RVS; - } - if (cpu->cfg.ext_u) { - ext |= RVU; - } - if (cpu->cfg.ext_h) { - ext |= RVH; - } - if (cpu->cfg.ext_v) { - int vext_version = VEXT_VERSION_1_00_0; - ext |= RVV; - if (!is_power_of_2(cpu->cfg.vlen)) { - error_setg(errp, - "Vector extension VLEN must be power of 2"); - return; - } - if (cpu->cfg.vlen > RV_VLEN_MAX || cpu->cfg.vlen < 128) { - error_setg(errp, - "Vector extension implementation only supports VLEN " - "in the range [128, %d]", RV_VLEN_MAX); - return; - } - if (!is_power_of_2(cpu->cfg.elen)) { - error_setg(errp, - "Vector extension ELEN must be power of 2"); - return; - } - if (cpu->cfg.elen > 64 || cpu->cfg.elen < 8) { - error_setg(errp, - "Vector extension implementation only supports ELEN " - "in the range [8, 64]"); - return; - } - if (cpu->cfg.vext_spec) { - if (!g_strcmp0(cpu->cfg.vext_spec, "v1.0")) { - vext_version = VEXT_VERSION_1_00_0; - } else { - error_setg(errp, - "Unsupported vector spec version '%s'", - cpu->cfg.vext_spec); - return; - } - } else { - qemu_log("vector version is not specified, " - "use the default value v1.0\n"); - } - set_vext_version(env, vext_version); - } - if (cpu->cfg.ext_j) { - ext |= RVJ; - } - - set_misa(env, env->misa_mxl, ext); + riscv_cpu_validate_set_extensions(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; } #ifndef CONFIG_USER_ONLY From 877a3a3732dcd45b09b96a6ff9655f6a2e19540f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 9 Jan 2023 23:26:55 +0800 Subject: [PATCH 149/814] target/riscv: Use TARGET_FMT_lx for env->mhartid env->mhartid is currently casted to long before printed, which drops the high 32-bit for rv64 on 32-bit host. Use TARGET_FMT_lx instead. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20230109152655.340114-1-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index c192d96a94..14a7027095 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -867,9 +867,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) (env->priv_ver < isa_edata_arr[i].min_version)) { isa_ext_update_enabled(cpu, &isa_edata_arr[i], false); #ifndef CONFIG_USER_ONLY - warn_report("disabling %s extension for hart 0x%lx because " - "privilege spec version does not match", - isa_edata_arr[i].name, (unsigned long)env->mhartid); + warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx + " because privilege spec version does not match", + isa_edata_arr[i].name, env->mhartid); #else warn_report("disabling %s extension because " "privilege spec version does not match", From 5dfe23774de34700337d66fc25b6313b65c34ad7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:39 -0300 Subject: [PATCH 150/814] hw/riscv/spike.c: simplify create_fdt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'mem_size' and 'cmdline' are unused. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index bff9475686..c7550abfc7 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -49,7 +49,6 @@ static const MemMapEntry spike_memmap[] = { }; static void create_fdt(SpikeState *s, const MemMapEntry *memmap, - uint64_t mem_size, const char *cmdline, bool is_32_bit, bool htif_custom_base) { void *fdt; @@ -299,8 +298,7 @@ static void spike_board_init(MachineState *machine) } /* Create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc[0]), htif_custom_base); + create_fdt(s, memmap, riscv_is_32bit(&s->soc[0]), htif_custom_base); /* Load kernel */ if (machine->kernel_filename) { From cdb785683ada2055f8f47ae154d0ce43f97d7a87 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:40 -0300 Subject: [PATCH 151/814] hw/riscv/virt.c: simplify create_fdt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'mem_size' and 'cmdline' aren't being used. Remove them. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-3-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 c8e35f861e..1921d3caa3 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -999,7 +999,7 @@ static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) } static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, - uint64_t mem_size, const char *cmdline, bool is_32_bit) + bool is_32_bit) { MachineState *mc = MACHINE(s); uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; @@ -1507,8 +1507,7 @@ static void virt_machine_init(MachineState *machine) virt_flash_map(s, system_memory); /* create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc[0])); + create_fdt(s, memmap, riscv_is_32bit(&s->soc[0])); s->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&s->machine_done); From f5be2ccb43d3d8466f15f53b82f5fdba1684fc56 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:41 -0300 Subject: [PATCH 152/814] hw/riscv/sifive_u.c: simplify create_fdt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'cmdline' isn't being used. Remove it. A MachineState pointer is being retrieved via a MACHINE() macro calling qdev_get_machine(). Use MACHINE(s) instead to avoid calling qdev(). 'mem_size' is being set as machine->ram_size by the caller. Retrieve it via ms->ram_size. Cc: Palmer Dabbelt Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index bac394c959..2fb6ee231f 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -94,9 +94,10 @@ static const MemMapEntry sifive_u_memmap[] = { #define GEM_REVISION 0x10070109 static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, - uint64_t mem_size, const char *cmdline, bool is_32_bit) + bool is_32_bit) { - MachineState *ms = MACHINE(qdev_get_machine()); + MachineState *ms = MACHINE(s); + uint64_t mem_size = ms->ram_size; void *fdt; int cpu, fdt_size; uint32_t *cells; @@ -560,8 +561,7 @@ static void sifive_u_machine_init(MachineState *machine) qemu_allocate_irq(sifive_u_machine_reset, NULL, 0)); /* create device tree */ - create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, - riscv_is_32bit(&s->soc.u_cpus)); + create_fdt(s, memmap, riscv_is_32bit(&s->soc.u_cpus)); if (s->start_in_flash) { /* From 914c97f968cc70be5275fd230d38f99882896032 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:42 -0300 Subject: [PATCH 153/814] hw/riscv/virt.c: remove 'is_32_bit' param from create_fdt_socket_cpus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create_fdt_socket_cpus() writes a different 'mmu-type' value if we're running in 32 or 64 bits. However, the flag is being calculated during virt_machine_init(), and is passed around in create_fdt(), then create_fdt_socket(), and then finally create_fdt_socket_cpus(). None of the intermediate functions are using the flag, which is a bit misleading. Remove 'is_32_bit' flag from create_fdt_socket_cpus() and calculate it using the already available RISCVVirtState pointer. This will also change the signature of create_fdt_socket() and create_fdt(), making it clear that these functions don't do anything special when we're running in 32 bit mode. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 1921d3caa3..99cb571024 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -223,12 +223,13 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, char *clust_name, uint32_t *phandle, - bool is_32_bit, uint32_t *intc_phandles) + uint32_t *intc_phandles) { int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); char *name, *cpu_name, *core_name, *intc_name; + bool is_32_bit = riscv_is_32bit(&s->soc[0]); for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -721,7 +722,7 @@ static void create_fdt_pmu(RISCVVirtState *s) } static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, - bool is_32_bit, uint32_t *phandle, + uint32_t *phandle, uint32_t *irq_mmio_phandle, uint32_t *irq_pcie_phandle, uint32_t *irq_virtio_phandle, @@ -750,7 +751,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_add_subnode(mc->fdt, clust_name); create_fdt_socket_cpus(s, socket, clust_name, phandle, - is_32_bit, &intc_phandles[phandle_pos]); + &intc_phandles[phandle_pos]); create_fdt_socket_memory(s, memmap, socket); @@ -998,8 +999,7 @@ static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) g_free(nodename); } -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, - bool is_32_bit) +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) { MachineState *mc = MACHINE(s); uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; @@ -1031,9 +1031,9 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2); qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2); - create_fdt_sockets(s, memmap, is_32_bit, &phandle, - &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, - &msi_pcie_phandle); + create_fdt_sockets(s, memmap, &phandle, &irq_mmio_phandle, + &irq_pcie_phandle, &irq_virtio_phandle, + &msi_pcie_phandle); create_fdt_virtio(s, memmap, irq_virtio_phandle); @@ -1507,7 +1507,7 @@ static void virt_machine_init(MachineState *machine) virt_flash_map(s, system_memory); /* create device tree */ - create_fdt(s, memmap, riscv_is_32bit(&s->soc[0])); + create_fdt(s, memmap); s->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&s->machine_done); From fb60b488cf5027c8134f1ce0c1df9b6bdd3b9276 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:43 -0300 Subject: [PATCH 154/814] hw/riscv: use MachineState::fdt in riscv_socket_fdt_write_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to use a MachineState pointer and a fdt pointer now that all RISC-V machines are using the FDT from the MachineState. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/numa.c | 6 +++--- hw/riscv/spike.c | 6 +++--- hw/riscv/virt.c | 18 +++++++++--------- include/hw/riscv/numa.h | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c index 7fe92d402f..f4343f5cde 100644 --- a/hw/riscv/numa.c +++ b/hw/riscv/numa.c @@ -156,11 +156,11 @@ uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id) ms->numa_state->nodes[socket_id].node_mem : 0; } -void riscv_socket_fdt_write_id(const MachineState *ms, void *fdt, - const char *node_name, int socket_id) +void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, + int socket_id) { if (numa_enabled(ms)) { - qemu_fdt_setprop_cell(fdt, node_name, "numa-node-id", socket_id); + qemu_fdt_setprop_cell(ms->fdt, node_name, "numa-node-id", socket_id); } } diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index c7550abfc7..5f12d80317 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -121,7 +121,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cell(fdt, cpu_name, "reg", s->soc[socket].hartid_base + cpu); qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); - riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket); + riscv_socket_fdt_write_id(mc, cpu_name, socket); qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle); intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name); @@ -154,7 +154,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cells(fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory"); - riscv_socket_fdt_write_id(mc, fdt, mem_name, socket); + riscv_socket_fdt_write_id(mc, mem_name, socket); g_free(mem_name); clint_addr = memmap[SPIKE_CLINT].base + @@ -167,7 +167,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, 0x0, clint_addr, 0x0, memmap[SPIKE_CLINT].size); qemu_fdt_setprop(fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); - riscv_socket_fdt_write_id(mc, fdt, clint_name, socket); + riscv_socket_fdt_write_id(mc, clint_name, socket); g_free(clint_name); g_free(clint_cells); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 99cb571024..6a2422a8cf 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -253,7 +253,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg", s->soc[socket].hartid_base + cpu); qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu"); - riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket); + riscv_socket_fdt_write_id(mc, cpu_name, socket); qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle); intc_phandles[cpu] = (*phandle)++; @@ -291,7 +291,7 @@ static void create_fdt_socket_memory(RISCVVirtState *s, qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory"); - riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket); + riscv_socket_fdt_write_id(mc, mem_name, socket); g_free(mem_name); } @@ -327,7 +327,7 @@ static void create_fdt_socket_clint(RISCVVirtState *s, 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); - riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket); + riscv_socket_fdt_write_id(mc, clint_name, socket); g_free(clint_name); g_free(clint_cells); @@ -372,7 +372,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, aclint_mswi_cells, aclint_cells_size); qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); - riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); + riscv_socket_fdt_write_id(mc, name, socket); g_free(name); } @@ -396,7 +396,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, 0x0, RISCV_ACLINT_DEFAULT_MTIME); qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", aclint_mtimer_cells, aclint_cells_size); - riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); + riscv_socket_fdt_write_id(mc, name, socket); g_free(name); if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { @@ -412,7 +412,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, aclint_sswi_cells, aclint_cells_size); qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); - riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); + riscv_socket_fdt_write_id(mc, name, socket); g_free(name); } @@ -471,7 +471,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s, 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRT_IRQCHIP_NUM_SOURCES - 1); - riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket); + riscv_socket_fdt_write_id(mc, plic_name, socket); qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle", plic_phandles[socket]); @@ -663,7 +663,7 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, aplic_s_phandle); qemu_fdt_setprop_cells(mc->fdt, aplic_name, "riscv,delegate", aplic_s_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES); - riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket); + riscv_socket_fdt_write_id(mc, aplic_name, socket); qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_m_phandle); g_free(aplic_name); @@ -691,7 +691,7 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, 0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_S].size); qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,num-sources", VIRT_IRQCHIP_NUM_SOURCES); - riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket); + riscv_socket_fdt_write_id(mc, aplic_name, socket); qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_s_phandle); if (!socket) { diff --git a/include/hw/riscv/numa.h b/include/hw/riscv/numa.h index 1a9cce3344..634df6673f 100644 --- a/include/hw/riscv/numa.h +++ b/include/hw/riscv/numa.h @@ -90,10 +90,10 @@ bool riscv_socket_check_hartids(const MachineState *ms, int socket_id); * @ms: pointer to machine state * @socket_id: socket index * - * Write NUMA node-id FDT property for given FDT node + * Write NUMA node-id FDT property in MachineState->fdt */ -void riscv_socket_fdt_write_id(const MachineState *ms, void *fdt, - const char *node_name, int socket_id); +void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, + int socket_id); /** * riscv_socket_fdt_write_distance_matrix: From 9c3ee7e84781909d5a114350c35554f0886491ba Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 11 Jan 2023 14:09:44 -0300 Subject: [PATCH 155/814] hw/riscv: use ms->fdt in riscv_socket_fdt_write_distance_matrix() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to use a MachineState pointer and a fdt pointer now that all RISC-V machines are using the FDT from the MachineState. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230111170948.316276-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/numa.c | 8 ++++---- hw/riscv/spike.c | 2 +- hw/riscv/virt.c | 2 +- include/hw/riscv/numa.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c index f4343f5cde..4720102561 100644 --- a/hw/riscv/numa.c +++ b/hw/riscv/numa.c @@ -164,7 +164,7 @@ void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, } } -void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt) +void riscv_socket_fdt_write_distance_matrix(const MachineState *ms) { int i, j, idx; uint32_t *dist_matrix, dist_matrix_size; @@ -184,10 +184,10 @@ void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt) } } - qemu_fdt_add_subnode(fdt, "/distance-map"); - qemu_fdt_setprop_string(fdt, "/distance-map", "compatible", + qemu_fdt_add_subnode(ms->fdt, "/distance-map"); + qemu_fdt_setprop_string(ms->fdt, "/distance-map", "compatible", "numa-distance-map-v1"); - qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix", + qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix", dist_matrix, dist_matrix_size); g_free(dist_matrix); } diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 5f12d80317..badc11ec43 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -174,7 +174,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, g_free(clust_name); } - riscv_socket_fdt_write_distance_matrix(mc, fdt); + riscv_socket_fdt_write_distance_matrix(mc); qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif"); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 6a2422a8cf..e6d4f06e8d 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -805,7 +805,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, } } - riscv_socket_fdt_write_distance_matrix(mc, mc->fdt); + riscv_socket_fdt_write_distance_matrix(mc); } static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, diff --git a/include/hw/riscv/numa.h b/include/hw/riscv/numa.h index 634df6673f..8f5280211d 100644 --- a/include/hw/riscv/numa.h +++ b/include/hw/riscv/numa.h @@ -100,9 +100,9 @@ void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, * @ms: pointer to machine state * @socket_id: socket index * - * Write NUMA distance matrix in FDT for given machine + * Write NUMA distance matrix in MachineState->fdt */ -void riscv_socket_fdt_write_distance_matrix(const MachineState *ms, void *fdt); +void riscv_socket_fdt_write_distance_matrix(const MachineState *ms); CpuInstanceProperties riscv_numa_cpu_index_to_props(MachineState *ms, unsigned cpu_index); From 06d85c24c28f42a57680dc21955e343f58d93089 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 15 Dec 2022 17:45:40 -0500 Subject: [PATCH 156/814] target/riscv: Fix up masking of vsip/vsie accesses The current logic attempts to shift the VS-level bits into their correct position in mip while leaving the remaining bits in-tact. This is both pointless and likely incorrect since one would expect that any new, future VS-level interrupts will get their own position in mip rather than sharing with their (H)S-level equivalent. Fix this, and make the logic more readable, by just making off the VS-level bits and shifting them into position. This also fixes reads of vsip, which would only ever report vsip.VSSIP since the non-writable bits got masked off as well. Fixes: d028ac7512f1 ("arget/riscv: Implement AIA CSRs for 64 local interrupts on RV32") Signed-off-by: Andrew Bresticker Reviewed-by: Alistair Francis Message-Id: <20221215224541.1423431-1-abrestic@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..270de7b1a8 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -2305,22 +2305,15 @@ static RISCVException rmw_vsie64(CPURISCVState *env, int csrno, uint64_t new_val, uint64_t wr_mask) { RISCVException ret; - uint64_t rval, vsbits, mask = env->hideleg & VS_MODE_INTERRUPTS; + uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS; /* Bring VS-level bits to correct position */ - vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); - new_val &= ~(VS_MODE_INTERRUPTS >> 1); - new_val |= vsbits << 1; - vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); - wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); - wr_mask |= vsbits << 1; + new_val = (new_val & (VS_MODE_INTERRUPTS >> 1)) << 1; + wr_mask = (wr_mask & (VS_MODE_INTERRUPTS >> 1)) << 1; ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & mask); if (ret_val) { - rval &= mask; - vsbits = rval & VS_MODE_INTERRUPTS; - rval &= ~VS_MODE_INTERRUPTS; - *ret_val = rval | (vsbits >> 1); + *ret_val = (rval & mask) >> 1; } return ret; @@ -2521,22 +2514,16 @@ static RISCVException rmw_vsip64(CPURISCVState *env, int csrno, uint64_t new_val, uint64_t wr_mask) { RISCVException ret; - uint64_t rval, vsbits, mask = env->hideleg & vsip_writable_mask; + uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS; /* Bring VS-level bits to correct position */ - vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); - new_val &= ~(VS_MODE_INTERRUPTS >> 1); - new_val |= vsbits << 1; - vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); - wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); - wr_mask |= vsbits << 1; + new_val = (new_val & (VS_MODE_INTERRUPTS >> 1)) << 1; + wr_mask = (wr_mask & (VS_MODE_INTERRUPTS >> 1)) << 1; - ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask & mask); + ret = rmw_mip64(env, csrno, &rval, new_val, + wr_mask & mask & vsip_writable_mask); if (ret_val) { - rval &= mask; - vsbits = rval & VS_MODE_INTERRUPTS; - rval &= ~VS_MODE_INTERRUPTS; - *ret_val = rval | (vsbits >> 1); + *ret_val = (rval & mask) >> 1; } return ret; From e471a8c9850f1af0c1bc5768ca28285348cdd6c5 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 15 Dec 2022 17:45:41 -0500 Subject: [PATCH 157/814] target/riscv: Trap on writes to stimecmp from VS when hvictl.VTI=1 Per the AIA specification, writes to stimecmp from VS level should trap when hvictl.VTI is set since the write may cause vsip.STIP to become unset. Fixes: 3ec0fe18a31f ("target/riscv: Add vstimecmp support") Signed-off-by: Andrew Bresticker Reviewed-by: Alistair Francis Message-Id: <20221215224541.1423431-2-abrestic@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 270de7b1a8..62e6c4acbd 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1037,6 +1037,9 @@ static RISCVException write_stimecmp(CPURISCVState *env, int csrno, RISCVCPU *cpu = env_archcpu(env); if (riscv_cpu_virt_enabled(env)) { + if (env->hvictl & HVICTL_VTI) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } return write_vstimecmp(env, csrno, val); } @@ -1057,6 +1060,9 @@ static RISCVException write_stimecmph(CPURISCVState *env, int csrno, RISCVCPU *cpu = env_archcpu(env); if (riscv_cpu_virt_enabled(env)) { + if (env->hvictl & HVICTL_VTI) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } return write_vstimecmph(env, csrno, val); } From 9d9db41373a256c5ae011c1428d26d2597a77484 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 17 Jan 2023 13:04:15 -1000 Subject: [PATCH 158/814] tcg/riscv: Use tcg_pcrel_diff in tcg_out_ldst We failed to update this with the w^x split, so misses the fact that true pc-relative offsets are usually small. Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Message-Id: <20230117230415.354239-1-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- tcg/riscv/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index fc0edd811f..01cb67ef7b 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -599,7 +599,7 @@ static void tcg_out_ldst(TCGContext *s, RISCVInsn opc, TCGReg data, intptr_t imm12 = sextreg(offset, 0, 12); if (offset != imm12) { - intptr_t diff = offset - (uintptr_t)s->code_ptr; + intptr_t diff = tcg_pcrel_diff(s, (void *)offset); if (addr == TCG_REG_ZERO && diff == (int32_t)diff) { imm12 = sextreg(diff, 0, 12); From 3ceeb19a53e51c0c6310d760d26dca08145797c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 15 Jan 2023 06:06:56 -1000 Subject: [PATCH 159/814] target/riscv: Introduce helper_set_rounding_mode_chkfrm The new helper always validates the contents of FRM, even if the new rounding mode is not DYN. This is required by the vector unit. Track whether we've validated FRM separately from whether we've updated fp_status with a given rounding mode, so that we can elide calls correctly. This partially reverts d6c4d3f2a69 which attempted the to do the same thing, but with two calls to gen_set_rm(), which is both inefficient and tickles an assertion in decode_save_opc. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1441 Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-Id: <20230115160657.3169274-2-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/fpu_helper.c | 37 +++++++++++++++++++++++++ target/riscv/helper.h | 1 + target/riscv/insn_trans/trans_rvv.c.inc | 24 +++------------- target/riscv/translate.c | 19 +++++++++++++ 4 files changed, 61 insertions(+), 20 deletions(-) diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 5699c9517f..96817df8ef 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -81,6 +81,43 @@ void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm) set_float_rounding_mode(softrm, &env->fp_status); } +void helper_set_rounding_mode_chkfrm(CPURISCVState *env, uint32_t rm) +{ + int softrm; + + /* Always validate frm, even if rm != DYN. */ + if (unlikely(env->frm >= 5)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } + if (rm == RISCV_FRM_DYN) { + rm = env->frm; + } + switch (rm) { + case RISCV_FRM_RNE: + softrm = float_round_nearest_even; + break; + case RISCV_FRM_RTZ: + softrm = float_round_to_zero; + break; + case RISCV_FRM_RDN: + softrm = float_round_down; + break; + case RISCV_FRM_RUP: + softrm = float_round_up; + break; + case RISCV_FRM_RMM: + softrm = float_round_ties_away; + break; + case RISCV_FRM_ROD: + softrm = float_round_to_odd; + break; + default: + g_assert_not_reached(); + } + + set_float_rounding_mode(softrm, &env->fp_status); +} + void helper_set_rod_rounding_mode(CPURISCVState *env) { set_float_rounding_mode(float_round_to_odd, &env->fp_status); diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 227c7122ef..9792ab5086 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -3,6 +3,7 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32) /* Floating Point - rounding mode */ DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_WG, void, env, i32) +DEF_HELPER_FLAGS_2(set_rounding_mode_chkfrm, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_1(set_rod_rounding_mode, TCG_CALL_NO_WG, void, env) /* Floating Point - fused */ diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index d455acedbf..bbb5c3a7b5 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2679,13 +2679,9 @@ static bool do_opfv(DisasContext *s, arg_rmr *a, int rm) { if (checkfn(s, a)) { - if (rm != RISCV_FRM_DYN) { - gen_set_rm(s, RISCV_FRM_DYN); - } - uint32_t data = 0; TCGLabel *over = gen_new_label(); - gen_set_rm(s, rm); + gen_set_rm_chkfrm(s, rm); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); @@ -2882,17 +2878,13 @@ static bool opffv_widen_check(DisasContext *s, arg_rmr *a) static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ { \ if (CHECK(s, a)) { \ - if (FRM != RISCV_FRM_DYN) { \ - gen_set_rm(s, RISCV_FRM_DYN); \ - } \ - \ uint32_t data = 0; \ static gen_helper_gvec_3_ptr * const fns[2] = { \ gen_helper_##HELPER##_h, \ gen_helper_##HELPER##_w, \ }; \ TCGLabel *over = gen_new_label(); \ - gen_set_rm(s, FRM); \ + gen_set_rm_chkfrm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ @@ -3005,17 +2997,13 @@ static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ { \ if (CHECK(s, a)) { \ - if (FRM != RISCV_FRM_DYN) { \ - gen_set_rm(s, RISCV_FRM_DYN); \ - } \ - \ uint32_t data = 0; \ static gen_helper_gvec_3_ptr * const fns[2] = { \ gen_helper_##HELPER##_h, \ gen_helper_##HELPER##_w, \ }; \ TCGLabel *over = gen_new_label(); \ - gen_set_rm(s, FRM); \ + gen_set_rm_chkfrm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ @@ -3060,10 +3048,6 @@ static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ { \ if (opxfv_narrow_check(s, a)) { \ - if (FRM != RISCV_FRM_DYN) { \ - gen_set_rm(s, RISCV_FRM_DYN); \ - } \ - \ uint32_t data = 0; \ static gen_helper_gvec_3_ptr * const fns[3] = { \ gen_helper_##HELPER##_b, \ @@ -3071,7 +3055,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ gen_helper_##HELPER##_w, \ }; \ TCGLabel *over = gen_new_label(); \ - gen_set_rm(s, FRM); \ + gen_set_rm_chkfrm(s, FRM); \ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ \ diff --git a/target/riscv/translate.c b/target/riscv/translate.c index df38db7553..493c3815e1 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -114,6 +114,8 @@ typedef struct DisasContext { bool pm_base_enabled; /* Use icount trigger for native debug */ bool itrigger; + /* FRM is known to contain a valid value. */ + bool frm_valid; /* TCG of the current insn_start */ TCGOp *insn_start; } DisasContext; @@ -674,12 +676,29 @@ static void gen_set_rm(DisasContext *ctx, int rm) gen_helper_set_rod_rounding_mode(cpu_env); return; } + if (rm == RISCV_FRM_DYN) { + /* The helper will return only if frm valid. */ + ctx->frm_valid = true; + } /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ decode_save_opc(ctx); gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm)); } +static void gen_set_rm_chkfrm(DisasContext *ctx, int rm) +{ + if (ctx->frm == rm && ctx->frm_valid) { + return; + } + ctx->frm = rm; + ctx->frm_valid = true; + + /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */ + decode_save_opc(ctx); + gen_helper_set_rounding_mode_chkfrm(cpu_env, tcg_constant_i32(rm)); +} + static int ex_plus_1(DisasContext *ctx, int nf) { return nf + 1; From f251c01a623e0c998a2127f8648d4d02cd04e702 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 15 Jan 2023 06:06:57 -1000 Subject: [PATCH 160/814] target/riscv: Remove helper_set_rod_rounding_mode The only setting of RISCV_FRM_ROD is from the vector unit, and now handled by helper_set_rounding_mode_chkfrm. This helper is now unused. Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20230115160657.3169274-3-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/fpu_helper.c | 5 ----- target/riscv/helper.h | 1 - target/riscv/translate.c | 4 ---- 3 files changed, 10 deletions(-) diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 96817df8ef..449d236df6 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -118,11 +118,6 @@ void helper_set_rounding_mode_chkfrm(CPURISCVState *env, uint32_t rm) set_float_rounding_mode(softrm, &env->fp_status); } -void helper_set_rod_rounding_mode(CPURISCVState *env) -{ - set_float_rounding_mode(float_round_to_odd, &env->fp_status); -} - static uint64_t do_fmadd_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2, uint64_t rs3, int flags) { diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 9792ab5086..58a30f03d6 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -4,7 +4,6 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32) /* Floating Point - rounding mode */ DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_2(set_rounding_mode_chkfrm, TCG_CALL_NO_WG, void, env, i32) -DEF_HELPER_FLAGS_1(set_rod_rounding_mode, TCG_CALL_NO_WG, void, env) /* Floating Point - fused */ DEF_HELPER_FLAGS_4(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 493c3815e1..01cc30a365 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -672,10 +672,6 @@ static void gen_set_rm(DisasContext *ctx, int rm) } ctx->frm = rm; - if (rm == RISCV_FRM_ROD) { - gen_helper_set_rod_rounding_mode(cpu_env); - return; - } if (rm == RISCV_FRM_DYN) { /* The helper will return only if frm valid. */ ctx->frm_valid = true; From b748352c555b42d497fe8ee00ee2e44eb8627660 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 17 Jan 2023 10:27:51 -0300 Subject: [PATCH 161/814] hw/riscv/virt.c: move create_fw_cfg() back to virt_machine_init() Commit 1c20d3ff6004 ("hw/riscv: virt: Add a machine done notifier") moved the initialization of fw_cfg to the virt_machine_done() callback. Problem is that the validation of fw_cfg by devices such as ramfb is done before the machine done notifier is called. Moving create_fw_cfg() to machine_done() results in QEMU failing to boot when using a ramfb device: ./qemu-system-riscv64 -machine virt -device ramfb -serial stdio qemu-system-riscv64: -device ramfb: ramfb device requires fw_cfg with DMA The fix is simple: move create_fw_cfg() config back to virt_machine_init(). This happens to be the same way the ARM 'virt' machine deals with fw_cfg (see machvirt_init() and virt_machine_done() in hw/arm/virt.c), so we're keeping consistency with how other machines handle this device. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1343 Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20230117132751.229738-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e6d4f06e8d..4a11b4b010 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1254,13 +1254,6 @@ static void virt_machine_done(Notifier *notifier, void *data) firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, start_addr, NULL); - /* - * 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); - rom_set_fw(s->fw_cfg); - if (drive_get(IF_PFLASH, 0, 1)) { /* * S-mode FW like EDK2 will be kept in second plash (unit 1). @@ -1468,6 +1461,13 @@ static void virt_machine_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, mask_rom); + /* + * 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); + rom_set_fw(s->fw_cfg); + /* SiFive Test MMIO device */ sifive_test_create(memmap[VIRT_TEST].base); From 68ba85cecc7a46ceb66c2f4b5e2165546821d062 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:14:34 +0100 Subject: [PATCH 162/814] coroutine: Split qemu/coroutine-core.h off qemu/coroutine.h qemu/coroutine.h and qemu/lockable.h include each other. They need each other only in macro expansions, so we could simply drop both inclusions to break the loop, and add suitable includes to files that expand the macros. Instead, move a part of qemu/coroutine.h to new qemu/coroutine-core.h so that qemu/coroutine-core.h doesn't need qemu/lockable.h, and qemu/lockable.h only needs qemu/coroutine-core.h. Result: qemu/coroutine.h includes qemu/lockable.h includes qemu/coroutine-core.h. Signed-off-by: Markus Armbruster Message-Id: <20221221131435.3851212-5-armbru@redhat.com> [Semantic rebase conflict with 7c10cb38cc "accel/tcg: Add debuginfo support" resolved] --- accel/tcg/debuginfo.h | 2 + hw/9pfs/coth.h | 2 +- include/block/aio.h | 2 +- include/io/channel.h | 2 +- include/qemu/coroutine-core.h | 154 ++++++++++++++++++++++++++++++++++ include/qemu/coroutine.h | 97 +-------------------- include/qemu/lockable.h | 2 +- include/qemu/typedefs.h | 1 - nbd/client-connection.c | 1 + tests/unit/test-aio.c | 2 +- ui/console.c | 1 + 11 files changed, 164 insertions(+), 102 deletions(-) create mode 100644 include/qemu/coroutine-core.h diff --git a/accel/tcg/debuginfo.h b/accel/tcg/debuginfo.h index 7542cfe6e0..f064e1c144 100644 --- a/accel/tcg/debuginfo.h +++ b/accel/tcg/debuginfo.h @@ -7,6 +7,8 @@ #ifndef ACCEL_TCG_DEBUGINFO_H #define ACCEL_TCG_DEBUGINFO_H +#include "qemu/bitops.h" + /* * Debuginfo describing a certain address. */ diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 1a1edbdc2a..2c54249b35 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -16,7 +16,7 @@ #define QEMU_9P_COTH_H #include "qemu/thread.h" -#include "qemu/coroutine.h" +#include "qemu/coroutine-core.h" #include "9p.h" /* diff --git a/include/block/aio.h b/include/block/aio.h index 0f65a3cc9e..3a546e7515 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -17,7 +17,7 @@ #ifdef CONFIG_LINUX_IO_URING #include #endif -#include "qemu/coroutine.h" +#include "qemu/coroutine-core.h" #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "qemu/thread.h" diff --git a/include/io/channel.h b/include/io/channel.h index f1b7e05f81..78b15f7870 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -22,7 +22,7 @@ #define QIO_CHANNEL_H #include "qom/object.h" -#include "qemu/coroutine.h" +#include "qemu/coroutine-core.h" #include "block/aio.h" #define TYPE_QIO_CHANNEL "qio-channel" diff --git a/include/qemu/coroutine-core.h b/include/qemu/coroutine-core.h new file mode 100644 index 0000000000..230bb56517 --- /dev/null +++ b/include/qemu/coroutine-core.h @@ -0,0 +1,154 @@ +/* + * QEMU coroutine implementation + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * Kevin Wolf + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_COROUTINE_CORE_H +#define QEMU_COROUTINE_CORE_H + +/** + * Coroutines are a mechanism for stack switching and can be used for + * cooperative userspace threading. These functions provide a simple but + * useful flavor of coroutines that is suitable for writing sequential code, + * rather than callbacks, for operations that need to give up control while + * waiting for events to complete. + * + * These functions are re-entrant and may be used outside the global mutex. + * + * Functions that execute in coroutine context cannot be called + * directly from normal functions. Use @coroutine_fn to mark such + * functions. For example: + * + * static void coroutine_fn foo(void) { + * .... + * } + * + * In the future it would be nice to have the compiler or a static + * checker catch misuse of such functions. This annotation might make + * it possible and in the meantime it serves as documentation. + */ + +/** + * Mark a function that executes in coroutine context + * + * + * Functions that execute in coroutine context cannot be called + * directly from normal functions. Use @coroutine_fn to mark such + * functions. For example: + * + * static void coroutine_fn foo(void) { + * .... + * } + * + * In the future it would be nice to have the compiler or a static + * checker catch misuse of such functions. This annotation might make + * it possible and in the meantime it serves as documentation. + */ + +typedef struct Coroutine Coroutine; +typedef struct CoMutex CoMutex; + +/** + * Coroutine entry point + * + * When the coroutine is entered for the first time, opaque is passed in as an + * argument. + * + * When this function returns, the coroutine is destroyed automatically and + * execution continues in the caller who last entered the coroutine. + */ +typedef void coroutine_fn CoroutineEntry(void *opaque); + +/** + * Create a new coroutine + * + * Use qemu_coroutine_enter() to actually transfer control to the coroutine. + * The opaque argument is passed as the argument to the entry point. + */ +Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque); + +/** + * Transfer control to a coroutine + */ +void qemu_coroutine_enter(Coroutine *coroutine); + +/** + * Transfer control to a coroutine if it's not active (i.e. part of the call + * stack of the running coroutine). Otherwise, do nothing. + */ +void qemu_coroutine_enter_if_inactive(Coroutine *co); + +/** + * Transfer control to a coroutine and associate it with ctx + */ +void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co); + +/** + * Transfer control back to a coroutine's caller + * + * This function does not return until the coroutine is re-entered using + * qemu_coroutine_enter(). + */ +void coroutine_fn qemu_coroutine_yield(void); + +/** + * Get the AioContext of the given coroutine + */ +AioContext *qemu_coroutine_get_aio_context(Coroutine *co); + +/** + * Get the currently executing coroutine + */ +Coroutine *qemu_coroutine_self(void); + +/** + * Return whether or not currently inside a coroutine + * + * This can be used to write functions that work both when in coroutine context + * and when not in coroutine context. Note that such functions cannot use the + * coroutine_fn annotation since they work outside coroutine context. + */ +bool qemu_in_coroutine(void); + +/** + * Return true if the coroutine is currently entered + * + * A coroutine is "entered" if it has not yielded from the current + * qemu_coroutine_enter() call used to run it. This does not mean that the + * coroutine is currently executing code since it may have transferred control + * to another coroutine using qemu_coroutine_enter(). + * + * When several coroutines enter each other there may be no way to know which + * ones have already been entered. In such situations this function can be + * used to avoid recursively entering coroutines. + */ +bool qemu_coroutine_entered(Coroutine *co); + +/** + * Initialises a CoMutex. This must be called before any other operation is used + * on the CoMutex. + */ +void qemu_co_mutex_init(CoMutex *mutex); + +/** + * Locks the mutex. If the lock cannot be taken immediately, control is + * transferred to the caller of the current coroutine. + */ +void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); + +/** + * Unlocks the mutex and schedules the next coroutine that was waiting for this + * lock to be run. + */ +void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); + +#endif diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 2496a4f4ef..a65be6697f 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -15,6 +15,7 @@ #ifndef QEMU_COROUTINE_H #define QEMU_COROUTINE_H +#include "qemu/coroutine-core.h" #include "qemu/queue.h" #include "qemu/timer.h" @@ -40,84 +41,6 @@ * it possible and in the meantime it serves as documentation. */ -typedef struct Coroutine Coroutine; - -/** - * Coroutine entry point - * - * When the coroutine is entered for the first time, opaque is passed in as an - * argument. - * - * When this function returns, the coroutine is destroyed automatically and - * execution continues in the caller who last entered the coroutine. - */ -typedef void coroutine_fn CoroutineEntry(void *opaque); - -/** - * Create a new coroutine - * - * Use qemu_coroutine_enter() to actually transfer control to the coroutine. - * The opaque argument is passed as the argument to the entry point. - */ -Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque); - -/** - * Transfer control to a coroutine - */ -void qemu_coroutine_enter(Coroutine *coroutine); - -/** - * Transfer control to a coroutine if it's not active (i.e. part of the call - * stack of the running coroutine). Otherwise, do nothing. - */ -void qemu_coroutine_enter_if_inactive(Coroutine *co); - -/** - * Transfer control to a coroutine and associate it with ctx - */ -void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co); - -/** - * Transfer control back to a coroutine's caller - * - * This function does not return until the coroutine is re-entered using - * qemu_coroutine_enter(). - */ -void coroutine_fn qemu_coroutine_yield(void); - -/** - * Get the AioContext of the given coroutine - */ -AioContext *qemu_coroutine_get_aio_context(Coroutine *co); - -/** - * Get the currently executing coroutine - */ -Coroutine *qemu_coroutine_self(void); - -/** - * Return whether or not currently inside a coroutine - * - * This can be used to write functions that work both when in coroutine context - * and when not in coroutine context. Note that such functions cannot use the - * coroutine_fn annotation since they work outside coroutine context. - */ -bool qemu_in_coroutine(void); - -/** - * Return true if the coroutine is currently entered - * - * A coroutine is "entered" if it has not yielded from the current - * qemu_coroutine_enter() call used to run it. This does not mean that the - * coroutine is currently executing code since it may have transferred control - * to another coroutine using qemu_coroutine_enter(). - * - * When several coroutines enter each other there may be no way to know which - * ones have already been entered. In such situations this function can be - * used to avoid recursively entering coroutines. - */ -bool qemu_coroutine_entered(Coroutine *co); - /** * Provides a mutex that can be used to synchronise coroutines */ @@ -145,24 +68,6 @@ struct CoMutex { Coroutine *holder; }; -/** - * Initialises a CoMutex. This must be called before any other operation is used - * on the CoMutex. - */ -void qemu_co_mutex_init(CoMutex *mutex); - -/** - * Locks the mutex. If the lock cannot be taken immediately, control is - * transferred to the caller of the current coroutine. - */ -void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); - -/** - * Unlocks the mutex and schedules the next coroutine that was waiting for this - * lock to be run. - */ -void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); - /** * Assert that the current coroutine holds @mutex. */ diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h index 86db7cb04c..9823220446 100644 --- a/include/qemu/lockable.h +++ b/include/qemu/lockable.h @@ -13,7 +13,7 @@ #ifndef QEMU_LOCKABLE_H #define QEMU_LOCKABLE_H -#include "qemu/coroutine.h" +#include "qemu/coroutine-core.h" #include "qemu/thread.h" typedef void QemuLockUnlockFunc(void *); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index fba04875c2..c7c8a85315 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -38,7 +38,6 @@ typedef struct BusState BusState; typedef struct Chardev Chardev; typedef struct Clock Clock; typedef struct CompatProperty CompatProperty; -typedef struct CoMutex CoMutex; typedef struct ConfidentialGuestSupport ConfidentialGuestSupport; typedef struct CPUAddressSpace CPUAddressSpace; typedef struct CPUArchState CPUArchState; diff --git a/nbd/client-connection.c b/nbd/client-connection.c index 0c5f917efa..e5b1046a1c 100644 --- a/nbd/client-connection.c +++ b/nbd/client-connection.c @@ -29,6 +29,7 @@ #include "qapi/qapi-visit-sockets.h" #include "qapi/clone-visitor.h" +#include "qemu/coroutine.h" struct NBDClientConnection { /* Initialization constants, never change */ diff --git a/tests/unit/test-aio.c b/tests/unit/test-aio.c index 178048d2f2..321d7ab01a 100644 --- a/tests/unit/test-aio.c +++ b/tests/unit/test-aio.c @@ -16,7 +16,7 @@ #include "qemu/timer.h" #include "qemu/sockets.h" #include "qemu/error-report.h" -#include "qemu/coroutine.h" +#include "qemu/coroutine-core.h" #include "qemu/main-loop.h" static AioContext *ctx; diff --git a/ui/console.c b/ui/console.c index 9ff9217f9b..ab43561fe1 100644 --- a/ui/console.c +++ b/ui/console.c @@ -27,6 +27,7 @@ #include "hw/qdev-core.h" #include "qapi/error.h" #include "qapi/qapi-commands-ui.h" +#include "qemu/coroutine.h" #include "qemu/fifo8.h" #include "qemu/main-loop.h" #include "qemu/module.h" From 436956013539c19cf781ae333bc1c125d728cf1f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:14:35 +0100 Subject: [PATCH 163/814] coroutine: Use Coroutine typedef name instead of structure tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20221221131435.3851212-6-armbru@redhat.com> --- include/block/aio.h | 7 +++---- util/async.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/block/aio.h b/include/block/aio.h index 3a546e7515..8fba6a3584 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -52,7 +52,6 @@ typedef void QEMUBHFunc(void *opaque); typedef bool AioPollFn(void *opaque); typedef void IOHandler(void *opaque); -struct Coroutine; struct ThreadPool; struct LinuxAioState; struct LuringState; @@ -694,7 +693,7 @@ static inline bool aio_node_check(AioContext *ctx, bool is_external) * is the context in which the coroutine is running (i.e. the value of * qemu_get_current_aio_context() from the coroutine itself). */ -void aio_co_schedule(AioContext *ctx, struct Coroutine *co); +void aio_co_schedule(AioContext *ctx, Coroutine *co); /** * aio_co_reschedule_self: @@ -717,7 +716,7 @@ void coroutine_fn aio_co_reschedule_self(AioContext *new_ctx); * context. The coroutine must not be entered by anyone else while * aio_co_wake() is active. */ -void aio_co_wake(struct Coroutine *co); +void aio_co_wake(Coroutine *co); /** * aio_co_enter: @@ -726,7 +725,7 @@ void aio_co_wake(struct Coroutine *co); * * Enter a coroutine in the specified AioContext. */ -void aio_co_enter(AioContext *ctx, struct Coroutine *co); +void aio_co_enter(AioContext *ctx, Coroutine *co); /** * Return the AioContext whose event loop runs in the current thread. diff --git a/util/async.c b/util/async.c index 14d63b3091..0657b75397 100644 --- a/util/async.c +++ b/util/async.c @@ -640,7 +640,7 @@ void coroutine_fn aio_co_reschedule_self(AioContext *new_ctx) } } -void aio_co_wake(struct Coroutine *co) +void aio_co_wake(Coroutine *co) { AioContext *ctx; @@ -653,7 +653,7 @@ void aio_co_wake(struct Coroutine *co) aio_co_enter(ctx, co); } -void aio_co_enter(AioContext *ctx, struct Coroutine *co) +void aio_co_enter(AioContext *ctx, Coroutine *co) { if (ctx != qemu_get_current_aio_context()) { aio_co_schedule(ctx, co); From e2c1c34f139f49ef909bb4322607fb8b39002312 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:35:49 +0100 Subject: [PATCH 164/814] include/block: Untangle inclusion loops We have two inclusion loops: block/block.h -> block/block-global-state.h -> block/block-common.h -> block/blockjob.h -> block/block.h block/block.h -> block/block-io.h -> block/block-common.h -> block/blockjob.h -> block/block.h I believe these go back to Emanuele's reorganization of the block API, merged a few months ago in commit d7e2fe4aac8. Fortunately, breaking them is merely a matter of deleting unnecessary includes from headers, and adding them back in places where they are now missing. Signed-off-by: Markus Armbruster Message-Id: <20221221133551.3967339-2-armbru@redhat.com> --- block.c | 1 + block/amend.c | 1 + block/backup.c | 1 + block/blkdebug.c | 1 + block/blklogwrites.c | 1 + block/blkreplay.c | 1 + block/blkverify.c | 1 + block/block-copy.c | 4 ++++ block/bochs.c | 1 + block/cloop.c | 1 + block/copy-before-write.c | 1 + block/copy-on-read.c | 1 + block/curl.c | 1 + block/dirty-bitmap.c | 2 ++ block/dmg.c | 1 + block/export/fuse.c | 3 ++- block/file-posix.c | 1 + block/file-win32.c | 1 + block/filter-compress.c | 1 + block/gluster.c | 1 + block/io.c | 1 + block/iscsi.c | 1 + block/mirror.c | 1 + block/monitor/bitmap-qmp-cmds.c | 2 ++ block/nfs.c | 1 + block/null.c | 1 + block/nvme.c | 1 + block/parallels-ext.c | 2 ++ block/preallocate.c | 1 + block/qapi-sysemu.c | 1 + block/qapi.c | 1 + block/qcow2-bitmap.c | 2 ++ block/qcow2-cache.c | 1 + block/qcow2-cluster.c | 1 + block/qcow2-refcount.c | 1 + block/qcow2-threads.c | 1 + block/qcow2.c | 1 + block/qed-check.c | 1 + block/qed-table.c | 1 + block/raw-format.c | 1 + block/rbd.c | 1 + block/ssh.c | 1 + block/throttle.c | 2 ++ block/vhdx-log.c | 1 + block/vvfat.c | 1 + block/win32-aio.c | 1 + block/write-threshold.c | 1 + blockdev.c | 1 + blockjob.c | 1 + hw/block/block.c | 1 + hw/sparc64/niagara.c | 1 + hw/virtio/virtio-pmem.c | 1 + include/block/block-common.h | 9 ++------- include/block/block-copy.h | 4 ++-- include/block/block-global-state.h | 4 +++- include/block/block-hmp-cmds.h | 2 ++ include/block/block-io.h | 5 ++++- include/block/block.h | 4 ++-- include/block/block_backup.h | 2 +- include/block/block_int-common.h | 14 +++++--------- include/block/block_int-global-state.h | 5 ++++- include/block/block_int-io.h | 4 +++- include/block/block_int.h | 4 ++-- include/block/blockjob.h | 2 +- include/block/blockjob_int.h | 1 - include/block/dirty-bitmap.h | 1 + include/block/qapi.h | 2 +- include/block/thread-pool.h | 2 +- include/block/throttle-groups.h | 2 +- include/sysemu/block-backend-io.h | 1 + migration/block-dirty-bitmap.c | 1 + migration/block.c | 1 + migration/savevm.c | 1 + monitor/qmp-cmds.c | 1 + nbd/server.c | 2 ++ qemu-img.c | 1 + scripts/block-coroutine-wrapper.py | 3 ++- softmmu/cpus.c | 1 + softmmu/physmem.c | 1 + storage-daemon/qemu-storage-daemon.c | 1 + target/i386/kvm/kvm.c | 1 + tests/unit/test-bdrv-drain.c | 2 +- tests/unit/test-block-iothread.c | 1 + 83 files changed, 112 insertions(+), 35 deletions(-) diff --git a/block.c b/block.c index 9c2ac757e4..b4a89207ad 100644 --- a/block.c +++ b/block.c @@ -27,6 +27,7 @@ #include "block/trace.h" #include "block/block_int.h" #include "block/blockjob.h" +#include "block/dirty-bitmap.h" #include "block/fuse.h" #include "block/nbd.h" #include "block/qdict.h" diff --git a/block/amend.c b/block/amend.c index f696a006e3..bc4bb7b416 100644 --- a/block/amend.c +++ b/block/amend.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/job.h" #include "qemu/main-loop.h" diff --git a/block/backup.c b/block/backup.c index 6a9ad97a53..824d39acaa 100644 --- a/block/backup.c +++ b/block/backup.c @@ -20,6 +20,7 @@ #include "block/blockjob_int.h" #include "block/block_backup.h" #include "block/block-copy.h" +#include "block/dirty-bitmap.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" diff --git a/block/blkdebug.c b/block/blkdebug.c index ca65b043f0..fa38c1cf7d 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/config-file.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "qemu/module.h" diff --git a/block/blklogwrites.c b/block/blklogwrites.c index cef9efe55d..a5bf767184 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/sockets.h" /* for EINPROGRESS on Windows */ +#include "block/block-io.h" #include "block/block_int.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" diff --git a/block/blkreplay.c b/block/blkreplay.c index 76a0b8d12a..e3b6a3efb2 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "block/block-io.h" #include "block/block_int.h" #include "sysemu/replay.h" #include "qapi/error.h" diff --git a/block/blkverify.c b/block/blkverify.c index c60a2dc624..0e78bc9dd6 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/sockets.h" /* for EINPROGRESS on Windows */ +#include "block/block-io.h" #include "block/block_int.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" diff --git a/block/block-copy.c b/block/block-copy.c index 5e59d6262f..30a4da0f2e 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -17,10 +17,14 @@ #include "trace.h" #include "qapi/error.h" #include "block/block-copy.h" +#include "block/block_int-io.h" +#include "block/dirty-bitmap.h" #include "block/reqlist.h" #include "sysemu/block-backend.h" #include "qemu/units.h" +#include "qemu/co-shared-resource.h" #include "qemu/coroutine.h" +#include "qemu/ratelimit.h" #include "block/aio_task.h" #include "qemu/error-report.h" #include "qemu/memalign.h" diff --git a/block/bochs.c b/block/bochs.c index e30e3908d9..46e7958316 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -24,6 +24,7 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qemu/bswap.h" diff --git a/block/cloop.c b/block/cloop.c index 3ff975a94d..1e5a52d6b2 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qemu/bswap.h" diff --git a/block/copy-before-write.c b/block/copy-before-write.c index 70c4ba7432..c9fb809ba0 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -32,6 +32,7 @@ #include "block/block_int.h" #include "block/qdict.h" #include "block/block-copy.h" +#include "block/dirty-bitmap.h" #include "block/copy-before-write.h" #include "block/reqlist.h" diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 815ac1d835..13ed4150a6 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -21,6 +21,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qapi/error.h" diff --git a/block/curl.c b/block/curl.c index cba4c4cac7..bf45fa3244 100644 --- a/block/curl.c +++ b/block/curl.c @@ -27,6 +27,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/option.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 956feeb2ae..1e7aee4010 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -24,8 +24,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "trace.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/blockjob.h" +#include "block/dirty-bitmap.h" #include "qemu/main-loop.h" struct BdrvDirtyBitmap { diff --git a/block/dmg.c b/block/dmg.c index 675e840ca5..e10b9a2ba5 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/bswap.h" #include "qemu/error-report.h" diff --git a/block/export/fuse.c b/block/export/fuse.c index 1b26ddfcf3..e5fc4af165 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -21,12 +21,13 @@ #include "qemu/osdep.h" #include "qemu/memalign.h" #include "block/aio.h" -#include "block/block.h" +#include "block/block_int-common.h" #include "block/export.h" #include "block/fuse.h" #include "block/qapi.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" +#include "qemu/main-loop.h" #include "sysemu/block-backend.h" #include diff --git a/block/file-posix.c b/block/file-posix.c index b9955db205..fa227d9d14 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qemu/option.h" diff --git a/block/file-win32.c b/block/file-win32.c index ec9d64d0e4..12be9c3d0f 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/cutils.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qemu/option.h" diff --git a/block/filter-compress.c b/block/filter-compress.c index 305716c86c..0ff8d28661 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/module.h" #include "qapi/error.h" diff --git a/block/gluster.c b/block/gluster.c index 7efc296399..1ad19ae915 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "qapi/error.h" diff --git a/block/io.c b/block/io.c index a09b1b34ab..a09a19f7a7 100644 --- a/block/io.c +++ b/block/io.c @@ -30,6 +30,7 @@ #include "block/blockjob_int.h" #include "block/block_int.h" #include "block/coroutines.h" +#include "block/dirty-bitmap.h" #include "block/write-threshold.h" #include "qemu/cutils.h" #include "qemu/memalign.h" diff --git a/block/iscsi.c b/block/iscsi.c index a316d46d96..c16c592042 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -33,6 +33,7 @@ #include "qemu/error-report.h" #include "qemu/bitops.h" #include "qemu/bitmap.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "scsi/constants.h" diff --git a/block/mirror.c b/block/mirror.c index 251adc5ae0..634815d78d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -18,6 +18,7 @@ #include "trace.h" #include "block/blockjob_int.h" #include "block/block_int.h" +#include "block/dirty-bitmap.h" #include "sysemu/block-backend.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c index 282363606f..55f778f5af 100644 --- a/block/monitor/bitmap-qmp-cmds.c +++ b/block/monitor/bitmap-qmp-cmds.c @@ -32,7 +32,9 @@ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" +#include "block/dirty-bitmap.h" #include "qapi/qapi-commands-block.h" #include "qapi/error.h" diff --git a/block/nfs.c b/block/nfs.c index ece22353ac..5e288dfc83 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -30,6 +30,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "trace.h" diff --git a/block/null.c b/block/null.c index 75f7d0db40..306e605fa1 100644 --- a/block/null.c +++ b/block/null.c @@ -16,6 +16,7 @@ #include "qapi/qmp/qstring.h" #include "qemu/module.h" #include "qemu/option.h" +#include "block/block-io.h" #include "block/block_int.h" #include "sysemu/replay.h" diff --git a/block/nvme.c b/block/nvme.c index 656624c585..1f1367640a 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -23,6 +23,7 @@ #include "qemu/option.h" #include "qemu/memalign.h" #include "qemu/vfio-helpers.h" +#include "block/block-io.h" #include "block/block_int.h" #include "sysemu/replay.h" #include "trace.h" diff --git a/block/parallels-ext.c b/block/parallels-ext.c index c9dbbf5089..8a109f005a 100644 --- a/block/parallels-ext.c +++ b/block/parallels-ext.c @@ -25,7 +25,9 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" +#include "block/dirty-bitmap.h" #include "parallels.h" #include "crypto/hash.h" #include "qemu/uuid.h" diff --git a/block/preallocate.c b/block/preallocate.c index d50ee7f49b..a51fc08515 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -30,6 +30,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/units.h" +#include "block/block-io.h" #include "block/block_int.h" diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c index 0c7a1423de..7bd7554150 100644 --- a/block/qapi-sysemu.c +++ b/block/qapi-sysemu.c @@ -32,6 +32,7 @@ #include "qemu/osdep.h" +#include "block/block_int.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" #include "qapi/qmp/qdict.h" diff --git a/block/qapi.c b/block/qapi.c index fea808425b..9b4da12966 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -26,6 +26,7 @@ #include "qemu/cutils.h" #include "block/qapi.h" #include "block/block_int.h" +#include "block/dirty-bitmap.h" #include "block/throttle-groups.h" #include "block/write-threshold.h" #include "qapi/error.h" diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index bcad567c0c..385260a1b5 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -26,6 +26,8 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" +#include "block/dirty-bitmap.h" #include "qapi/error.h" #include "qemu/cutils.h" diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 54b2d5f4de..01c67bdddc 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "qemu/memalign.h" #include "qcow2.h" #include "trace.h" diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 40ed847f97..870be106b6 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include +#include "block/block-io.h" #include "qapi/error.h" #include "qcow2.h" #include "qemu/bswap.h" diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 81264740f0..5ffbefee2e 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "qapi/error.h" #include "qcow2.h" #include "qemu/range.h" diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c index 1914baf456..953bbe6df8 100644 --- a/block/qcow2-threads.c +++ b/block/qcow2-threads.c @@ -34,6 +34,7 @@ #endif #include "qcow2.h" +#include "block/block-io.h" #include "block/thread-pool.h" #include "crypto.h" diff --git a/block/qcow2.c b/block/qcow2.c index bafbd077b9..2e9c57e269 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -43,6 +43,7 @@ #include "qapi/qapi-visit-block-core.h" #include "crypto.h" #include "block/aio_task.h" +#include "block/dirty-bitmap.h" /* Differences with QCOW: diff --git a/block/qed-check.c b/block/qed-check.c index 418033ee24..a6612be00f 100644 --- a/block/qed-check.c +++ b/block/qed-check.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "qed.h" typedef struct { diff --git a/block/qed-table.c b/block/qed-table.c index aa203f2627..e41c87a157 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -13,6 +13,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "trace.h" #include "qemu/sockets.h" /* for EINPROGRESS on Windows */ #include "qed.h" diff --git a/block/raw-format.c b/block/raw-format.c index 28905b09ee..b6a0ce58f4 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -27,6 +27,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qapi/error.h" #include "qemu/module.h" diff --git a/block/rbd.c b/block/rbd.c index 3aa6aae0e0..6167c5e424 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -18,6 +18,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/option.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "crypto/secret.h" diff --git a/block/ssh.c b/block/ssh.c index 8508710f2f..8bd2a134c1 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -27,6 +27,7 @@ #include #include +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "qapi/error.h" diff --git a/block/throttle.c b/block/throttle.c index 88851c84f4..00cb46d0e5 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -18,6 +18,8 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" +#include "block/block_int.h" #include "block/throttle-groups.h" #include "qemu/module.h" #include "qemu/option.h" diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 572582b87b..c48cf65d62 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" #include "qemu/error-report.h" #include "qemu/bswap.h" diff --git a/block/vvfat.c b/block/vvfat.c index 723c91216e..d7d775bd2c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -27,6 +27,7 @@ #include #include #include "qapi/error.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/qdict.h" #include "qemu/module.h" diff --git a/block/win32-aio.c b/block/win32-aio.c index aadc7b1bc3..ee87d6048f 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/aio.h" #include "block/raw-aio.h" diff --git a/block/write-threshold.c b/block/write-threshold.c index 35cafbc22d..76d8885677 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "block/block-io.h" #include "block/block_int.h" #include "block/write-threshold.h" #include "qapi/error.h" diff --git a/blockdev.c b/blockdev.c index ebf952cd21..fe9d8d89c0 100644 --- a/blockdev.c +++ b/blockdev.c @@ -35,6 +35,7 @@ #include "sysemu/blockdev.h" #include "hw/block/block.h" #include "block/blockjob.h" +#include "block/dirty-bitmap.h" #include "block/qdict.h" #include "block/throttle-groups.h" #include "monitor/monitor.h" diff --git a/blockjob.c b/blockjob.c index 54b4091a36..659c3cb9de 100644 --- a/blockjob.c +++ b/blockjob.c @@ -24,6 +24,7 @@ */ #include "qemu/osdep.h" +#include "block/aio-wait.h" #include "block/block.h" #include "block/blockjob_int.h" #include "block/block_int.h" diff --git a/hw/block/block.c b/hw/block/block.c index f9c4fe6767..ddcef71f80 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "block/block_int-common.h" #include "sysemu/blockdev.h" #include "sysemu/block-backend.h" #include "hw/block/block.h" diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index ccad2c43a3..ab3c4ec346 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "block/block_int-common.h" #include "qemu/units.h" #include "cpu.h" #include "hw/boards.h" diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index a1abfe0e1b..dff402f08f 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include "qemu/main-loop.h" #include "hw/virtio/virtio-pmem.h" #include "hw/qdev-properties.h" diff --git a/include/block/block-common.h b/include/block/block-common.h index 434ffc5d34..41686810de 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -24,12 +24,8 @@ #ifndef BLOCK_COMMON_H #define BLOCK_COMMON_H -#include "block/aio.h" -#include "block/aio-wait.h" -#include "qemu/iov.h" -#include "block/accounting.h" -#include "qemu/hbitmap.h" -#include "qemu/transactions.h" +#include "qapi/qapi-types-block-core.h" +#include "qemu/queue.h" /* * co_wrapper{*}: Function specifiers used by block-coroutine-wrapper.py @@ -55,7 +51,6 @@ #define co_wrapper_bdrv_rdlock #define co_wrapper_mixed_bdrv_rdlock -#include "block/dirty-bitmap.h" #include "block/blockjob.h" /* block.c */ diff --git a/include/block/block-copy.h b/include/block/block-copy.h index 8cea4f9b90..d0f8386554 100644 --- a/include/block/block-copy.h +++ b/include/block/block-copy.h @@ -15,8 +15,8 @@ #ifndef BLOCK_COPY_H #define BLOCK_COPY_H -#include "block/block.h" -#include "qemu/co-shared-resource.h" +#include "block/block-common.h" +#include "qemu/progress_meter.h" /* All APIs are thread-safe */ diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index b0a3cfe6b8..a38f86dc15 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -24,7 +24,9 @@ #ifndef BLOCK_GLOBAL_STATE_H #define BLOCK_GLOBAL_STATE_H -#include "block-common.h" +#include "block/block-common.h" +#include "qemu/coroutine.h" +#include "qemu/transactions.h" /* * Global state (GS) API. These functions run under the BQL. diff --git a/include/block/block-hmp-cmds.h b/include/block/block-hmp-cmds.h index ba0593c440..71113cd7ef 100644 --- a/include/block/block-hmp-cmds.h +++ b/include/block/block-hmp-cmds.h @@ -15,6 +15,8 @@ #ifndef BLOCK_BLOCK_HMP_CMDS_H #define BLOCK_BLOCK_HMP_CMDS_H +#include "qemu/coroutine.h" + void hmp_drive_add(Monitor *mon, const QDict *qdict); void hmp_commit(Monitor *mon, const QDict *qdict); diff --git a/include/block/block-io.h b/include/block/block-io.h index 2ed6214909..3398351596 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -24,7 +24,10 @@ #ifndef BLOCK_IO_H #define BLOCK_IO_H -#include "block-common.h" +#include "block/aio-wait.h" +#include "block/block-common.h" +#include "qemu/coroutine.h" +#include "qemu/iov.h" /* * I/O API functions. These functions are thread-safe, and therefore diff --git a/include/block/block.h b/include/block/block.h index 1e6b8fef1e..e2c647de27 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -24,8 +24,8 @@ #ifndef BLOCK_H #define BLOCK_H -#include "block-global-state.h" -#include "block-io.h" +#include "block/block-global-state.h" +#include "block/block-io.h" /* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ diff --git a/include/block/block_backup.h b/include/block/block_backup.h index 157596c296..4d4d5ba153 100644 --- a/include/block/block_backup.h +++ b/include/block/block_backup.h @@ -18,7 +18,7 @@ #ifndef BLOCK_BACKUP_H #define BLOCK_BACKUP_H -#include "block/block_int.h" +#include "block/blockjob.h" void backup_do_checkpoint(BlockJob *job, Error **errp); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index c34c525fa6..887ace7dbd 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -24,17 +24,13 @@ #ifndef BLOCK_INT_COMMON_H #define BLOCK_INT_COMMON_H -#include "block/accounting.h" -#include "block/block.h" -#include "block/aio-wait.h" -#include "qemu/queue.h" -#include "qemu/coroutine.h" -#include "qemu/stats64.h" -#include "qemu/timer.h" -#include "qemu/hbitmap.h" +#include "block/aio.h" +#include "block/block-common.h" +#include "block/block-global-state.h" #include "block/snapshot.h" -#include "qemu/throttle.h" +#include "qemu/iov.h" #include "qemu/rcu.h" +#include "qemu/stats64.h" #define BLOCK_FLAG_LAZY_REFCOUNTS 8 diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h index 2f0993f6e9..902406eb99 100644 --- a/include/block/block_int-global-state.h +++ b/include/block/block_int-global-state.h @@ -25,7 +25,10 @@ #ifndef BLOCK_INT_GLOBAL_STATE_H #define BLOCK_INT_GLOBAL_STATE_H -#include "block_int-common.h" +#include "block/blockjob.h" +#include "block/block_int-common.h" +#include "qemu/hbitmap.h" +#include "qemu/main-loop.h" /* * Global state (GS) API. These functions run under the BQL. diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 8bc061ebb8..44367219f4 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -24,7 +24,9 @@ #ifndef BLOCK_INT_IO_H #define BLOCK_INT_IO_H -#include "block_int-common.h" +#include "block/block_int-common.h" +#include "qemu/hbitmap.h" +#include "qemu/main-loop.h" /* * I/O API functions. These functions are thread-safe. diff --git a/include/block/block_int.h b/include/block/block_int.h index b35b0138ed..567a178e13 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -24,8 +24,8 @@ #ifndef BLOCK_INT_H #define BLOCK_INT_H -#include "block_int-global-state.h" -#include "block_int-io.h" +#include "block/block_int-global-state.h" +#include "block/block_int-io.h" #include "block/graph-lock.h" /* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */ diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 03032b2eca..058b0c824c 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -26,8 +26,8 @@ #ifndef BLOCKJOB_H #define BLOCKJOB_H +#include "qapi/qapi-types-block-core.h" #include "qemu/job.h" -#include "block/block.h" #include "qemu/ratelimit.h" #define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */ diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h index 6bd9ae2b20..f008446285 100644 --- a/include/block/blockjob_int.h +++ b/include/block/blockjob_int.h @@ -27,7 +27,6 @@ #define BLOCKJOB_INT_H #include "block/blockjob.h" -#include "block/block.h" /** * BlockJobDriver: diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index c3700cec76..233535ef2d 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -1,6 +1,7 @@ #ifndef BLOCK_DIRTY_BITMAP_H #define BLOCK_DIRTY_BITMAP_H +#include "block/block-common.h" #include "qapi/qapi-types-block-core.h" #include "qemu/hbitmap.h" diff --git a/include/block/qapi.h b/include/block/qapi.h index 22c7807c89..865fb974d4 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -25,8 +25,8 @@ #ifndef BLOCK_QAPI_H #define BLOCK_QAPI_H -#include "block/block.h" #include "block/snapshot.h" +#include "qapi/qapi-types-block-core.h" BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs, diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h index 2020bcc92d..95ff2b0bdb 100644 --- a/include/block/thread-pool.h +++ b/include/block/thread-pool.h @@ -18,7 +18,7 @@ #ifndef QEMU_THREAD_POOL_H #define QEMU_THREAD_POOL_H -#include "block/block.h" +#include "block/aio.h" #define THREAD_POOL_MAX_THREADS_DEFAULT 64 diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h index 9541b32432..ff282fc0f8 100644 --- a/include/block/throttle-groups.h +++ b/include/block/throttle-groups.h @@ -25,8 +25,8 @@ #ifndef THROTTLE_GROUPS_H #define THROTTLE_GROUPS_H +#include "qemu/coroutine.h" #include "qemu/throttle.h" -#include "block/block_int.h" #include "qom/object.h" /* The ThrottleGroupMember structure indicates membership in a ThrottleGroup diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 7ec6d978d4..031a27ba10 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -14,6 +14,7 @@ #define BLOCK_BACKEND_IO_H #include "block-backend-common.h" +#include "block/accounting.h" /* * I/O API functions. These functions are thread-safe. diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 283017d7d3..15127d489a 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -61,6 +61,7 @@ #include "qemu/osdep.h" #include "block/block.h" #include "block/block_int.h" +#include "block/dirty-bitmap.h" #include "sysemu/block-backend.h" #include "sysemu/runstate.h" #include "qemu/main-loop.h" diff --git a/migration/block.c b/migration/block.c index 4347da1526..5da15a62de 100644 --- a/migration/block.c +++ b/migration/block.c @@ -20,6 +20,7 @@ #include "qemu/cutils.h" #include "qemu/queue.h" #include "block.h" +#include "block/dirty-bitmap.h" #include "migration/misc.h" #include "migration.h" #include "migration/register.h" diff --git a/migration/savevm.c b/migration/savevm.c index a0cdb714f7..a783789430 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -52,6 +52,7 @@ #include "exec/target_page.h" #include "trace.h" #include "qemu/iov.h" +#include "qemu/job.h" #include "qemu/main-loop.h" #include "block/snapshot.h" #include "qemu/cutils.h" diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 2932b3f3a5..e0e1fdf507 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -14,6 +14,7 @@ */ #include "qemu/osdep.h" +#include "block/blockjob.h" #include "qemu/cutils.h" #include "qemu/option.h" #include "monitor/monitor.h" diff --git a/nbd/server.c b/nbd/server.c index 67ed333578..a4750e4188 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" +#include "block/block_int.h" #include "block/export.h" +#include "block/dirty-bitmap.h" #include "qapi/error.h" #include "qemu/queue.h" #include "trace.h" diff --git a/qemu-img.c b/qemu-img.c index 439d8de1e3..7e73c5c1da 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -48,6 +48,7 @@ #include "sysemu/block-backend.h" #include "block/block_int.h" #include "block/blockjob.h" +#include "block/dirty-bitmap.h" #include "block/qapi.h" #include "crypto/init.h" #include "trace/control.h" diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index 6e087fa0b7..dff3af49f5 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -42,7 +42,8 @@ def gen_header(): #include "qemu/osdep.h" #include "block/coroutines.h" #include "block/block-gen.h" -#include "block/block_int.h"\ +#include "block/block_int.h" +#include "block/dirty-bitmap.h" """ diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 5a584a8d57..9cbc8172b5 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -34,6 +34,7 @@ #include "sysemu/hw_accel.h" #include "exec/cpu-common.h" #include "qemu/thread.h" +#include "qemu/main-loop.h" #include "qemu/plugin.h" #include "sysemu/cpus.h" #include "qemu/guest-random.h" diff --git a/softmmu/physmem.c b/softmmu/physmem.c index edec095c7a..cd5b6a1634 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -23,6 +23,7 @@ #include "qemu/cutils.h" #include "qemu/cacheflush.h" +#include "qemu/hbitmap.h" #include "qemu/madvise.h" #ifdef CONFIG_TCG diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c index 7718f6dcda..da19498c66 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -48,6 +48,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/help_option.h" +#include "qemu/job.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 0ab4e0734a..5870301991 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -37,6 +37,7 @@ #include "exec/gdbstub.h" #include "qemu/host-utils.h" #include "qemu/main-loop.h" +#include "qemu/ratelimit.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/memalign.h" diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index 8cedea4959..4fed8b751f 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" -#include "block/block.h" +#include "block/block_int.h" #include "block/blockjob_int.h" #include "sysemu/block-backend.h" #include "qapi/error.h" diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 8ca5adec5e..ff5147f619 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "block/block.h" +#include "block/block_int-global-state.h" #include "block/blockjob_int.h" #include "sysemu/block-backend.h" #include "qapi/error.h" From 1881f336a33a8a99cb17ab1c57ed953682e8e107 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:35:50 +0100 Subject: [PATCH 165/814] hw/sparc64/niagara: Use blk_name() instead of open-coding it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20221221133551.3967339-3-armbru@redhat.com> --- hw/sparc64/niagara.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index ab3c4ec346..6725cc61fd 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "block/block_int-common.h" #include "qemu/units.h" #include "cpu.h" #include "hw/boards.h" @@ -144,10 +143,9 @@ static void niagara_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), NIAGARA_VDISK_BASE, &s->vdisk_ram); dinfo->is_default = 1; - rom_add_file_fixed(blk_bs(blk)->filename, NIAGARA_VDISK_BASE, -1); + rom_add_file_fixed(blk_name(blk), NIAGARA_VDISK_BASE, -1); } else { - error_report("could not load ram disk '%s'", - blk_bs(blk)->filename); + error_report("could not load ram disk '%s'", blk_name(blk)); exit(1); } } From 82651e8792344ccc526f505fdf1c8c56f0d18881 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 Dec 2022 14:35:51 +0100 Subject: [PATCH 166/814] include/hw/block: Include hw/block/block.h where needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/block/swim.h needs BlockConf. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20221221133551.3967339-4-armbru@redhat.com> --- include/hw/block/swim.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/block/swim.h b/include/hw/block/swim.h index c1bd5f6555..9b3dcb029d 100644 --- a/include/hw/block/swim.h +++ b/include/hw/block/swim.h @@ -11,6 +11,7 @@ #ifndef SWIM_H #define SWIM_H +#include "hw/block/block.h" #include "hw/sysbus.h" #include "qom/object.h" From 2c6fe2e2140965d93d0f950f80eee8e559b760f3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 22 Dec 2022 11:46:25 +0100 Subject: [PATCH 167/814] include/hw/ppc: Split pnv_chip.h off pnv.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PnvChipClass, PnvChip, Pnv8Chip, Pnv9Chip, and Pnv10Chip are defined in pnv.h. Many users of the header don't actually need them. One instance is this inclusion loop: hw/ppc/pnv_homer.h includes hw/ppc/pnv.h for typedef PnvChip, and vice versa for struct PnvHomer. Similar structs live in their own headers: PnvHomerClass and PnvHomer in pnv_homer.h, PnvLpcClass and PnvLpcController in pci_lpc.h, PnvPsiClass, PnvPsi, Pnv8Psi, Pnv9Psi, Pnv10Psi in pnv_psi.h, ... Move PnvChipClass, PnvChip, Pnv8Chip, Pnv9Chip, and Pnv10Chip to new pnv_chip.h, and adjust include directives. This breaks the inclusion loop mentioned above. Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Reviewed-by: Daniel Henrique Barboza Message-Id: <20221222104628.659681-2-armbru@redhat.com> --- hw/intc/pnv_xive.c | 1 + hw/intc/pnv_xive2.c | 1 + hw/pci-host/pnv_phb3.c | 1 + hw/pci-host/pnv_phb4_pec.c | 1 + hw/ppc/pnv.c | 3 + hw/ppc/pnv_core.c | 1 + hw/ppc/pnv_homer.c | 1 + hw/ppc/pnv_lpc.c | 1 + hw/ppc/pnv_xscom.c | 1 + include/hw/ppc/pnv.h | 143 +----------------------------------- include/hw/ppc/pnv_chip.h | 147 +++++++++++++++++++++++++++++++++++++ 11 files changed, 160 insertions(+), 141 deletions(-) create mode 100644 include/hw/ppc/pnv_chip.h diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index c7b75ed12e..622f9d28b7 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -18,6 +18,7 @@ #include "monitor/monitor.h" #include "hw/ppc/fdt.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_core.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/pnv_xive.h" diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index f22ce5ca59..7176d70234 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -16,6 +16,7 @@ #include "monitor/monitor.h" #include "hw/ppc/fdt.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_core.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/xive2.h" diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 9054c393a2..7a21497cf8 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -16,6 +16,7 @@ #include "hw/pci/pcie_host.h" #include "hw/pci/pcie_port.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "qom/object.h" diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 9871f462cd..43267a428f 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -17,6 +17,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 3d01e26f84..44b1fbbc93 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -44,9 +44,12 @@ #include "target/ppc/mmu-hash64.h" #include "hw/pci/msi.h" #include "hw/pci-host/pnv_phb.h" +#include "hw/pci-host/pnv_phb3.h" +#include "hw/pci-host/pnv_phb4.h" #include "hw/ppc/xics.h" #include "hw/qdev-properties.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/pnv_pnor.h" diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 9ee79192dd..410f31bdf8 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -25,6 +25,7 @@ #include "target/ppc/cpu.h" #include "hw/ppc/ppc.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_core.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/xics.h" diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c index ea73919e54..f9a203d11d 100644 --- a/hw/ppc/pnv_homer.c +++ b/hw/ppc/pnv_homer.c @@ -25,6 +25,7 @@ #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_homer.h" #include "hw/ppc/pnv_xscom.h" diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index ee890e7ab4..71143b7692 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -26,6 +26,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 79f10de57f..d820e05e40 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -26,6 +26,7 @@ #include "hw/ppc/fdt.h" #include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_chip.h" #include "hw/ppc/pnv_xscom.h" #include diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 9ef7e2d0dc..ca49e4281d 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -20,158 +20,19 @@ #ifndef PPC_PNV_H #define PPC_PNV_H +#include "cpu.h" #include "hw/boards.h" #include "hw/sysbus.h" #include "hw/ipmi/ipmi.h" -#include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_pnor.h" -#include "hw/ppc/pnv_psi.h" -#include "hw/ppc/pnv_occ.h" -#include "hw/ppc/pnv_sbe.h" -#include "hw/ppc/pnv_homer.h" -#include "hw/ppc/pnv_xive.h" -#include "hw/ppc/pnv_core.h" -#include "hw/pci-host/pnv_phb3.h" -#include "hw/pci-host/pnv_phb4.h" #include "hw/pci-host/pnv_phb.h" -#include "qom/object.h" #define TYPE_PNV_CHIP "pnv-chip" -OBJECT_DECLARE_TYPE(PnvChip, PnvChipClass, - PNV_CHIP) -struct PnvChip { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - uint32_t chip_id; - uint64_t ram_start; - uint64_t ram_size; - - uint32_t nr_cores; - uint32_t nr_threads; - uint64_t cores_mask; - PnvCore **cores; - - uint32_t num_pecs; - - MemoryRegion xscom_mmio; - MemoryRegion xscom; - AddressSpace xscom_as; - - MemoryRegion *fw_mr; - gchar *dt_isa_nodename; -}; - -#define TYPE_PNV8_CHIP "pnv8-chip" +typedef struct PnvChip PnvChip; typedef struct Pnv8Chip Pnv8Chip; -DECLARE_INSTANCE_CHECKER(Pnv8Chip, PNV8_CHIP, - TYPE_PNV8_CHIP) - -struct Pnv8Chip { - /*< private >*/ - PnvChip parent_obj; - - /*< public >*/ - MemoryRegion icp_mmio; - - PnvLpcController lpc; - Pnv8Psi psi; - PnvOCC occ; - PnvHomer homer; - -#define PNV8_CHIP_PHB3_MAX 4 - /* - * The array is used to allow quick access to the phbs by - * pnv_ics_get_child() and pnv_ics_resend_child(). - */ - PnvPHB *phbs[PNV8_CHIP_PHB3_MAX]; - uint32_t num_phbs; - - XICSFabric *xics; -}; - -#define TYPE_PNV9_CHIP "pnv9-chip" typedef struct Pnv9Chip Pnv9Chip; -DECLARE_INSTANCE_CHECKER(Pnv9Chip, PNV9_CHIP, - TYPE_PNV9_CHIP) - -struct Pnv9Chip { - /*< private >*/ - PnvChip parent_obj; - - /*< public >*/ - PnvXive xive; - Pnv9Psi psi; - PnvLpcController lpc; - PnvOCC occ; - PnvSBE sbe; - PnvHomer homer; - - uint32_t nr_quads; - PnvQuad *quads; - -#define PNV9_CHIP_MAX_PEC 3 - PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC]; -}; - -/* - * A SMT8 fused core is a pair of SMT4 cores. - */ -#define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf) -#define PNV9_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) - -#define TYPE_PNV10_CHIP "pnv10-chip" typedef struct Pnv10Chip Pnv10Chip; -DECLARE_INSTANCE_CHECKER(Pnv10Chip, PNV10_CHIP, - TYPE_PNV10_CHIP) - -struct Pnv10Chip { - /*< private >*/ - PnvChip parent_obj; - - /*< public >*/ - PnvXive2 xive; - Pnv9Psi psi; - PnvLpcController lpc; - PnvOCC occ; - PnvSBE sbe; - PnvHomer homer; - - uint32_t nr_quads; - PnvQuad *quads; - -#define PNV10_CHIP_MAX_PEC 2 - PnvPhb4PecState pecs[PNV10_CHIP_MAX_PEC]; -}; - -#define PNV10_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf) -#define PNV10_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) - -struct PnvChipClass { - /*< private >*/ - SysBusDeviceClass parent_class; - - /*< public >*/ - uint64_t chip_cfam_id; - uint64_t cores_mask; - uint32_t num_pecs; - uint32_t num_phbs; - - DeviceRealize parent_realize; - - uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id); - void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp); - void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu); - void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu); - void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, Monitor *mon); - ISABus *(*isa_create)(PnvChip *chip, Error **errp); - void (*dt_populate)(PnvChip *chip, void *fdt); - void (*pic_print_info)(PnvChip *chip, Monitor *mon); - uint64_t (*xscom_core_base)(PnvChip *chip, uint32_t core_id); - uint32_t (*xscom_pcba)(PnvChip *chip, uint64_t addr); -}; #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP #define PNV_CHIP_TYPE_NAME(cpu_model) cpu_model PNV_CHIP_TYPE_SUFFIX diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h new file mode 100644 index 0000000000..53e1d921d7 --- /dev/null +++ b/include/hw/ppc/pnv_chip.h @@ -0,0 +1,147 @@ +#ifndef PPC_PNV_CHIP_H +#define PPC_PNV_CHIP_H + +#include "hw/pci-host/pnv_phb4.h" +#include "hw/ppc/pnv_core.h" +#include "hw/ppc/pnv_homer.h" +#include "hw/ppc/pnv_lpc.h" +#include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_psi.h" +#include "hw/ppc/pnv_sbe.h" +#include "hw/ppc/pnv_xive.h" +#include "hw/sysbus.h" + +OBJECT_DECLARE_TYPE(PnvChip, PnvChipClass, + PNV_CHIP) + +struct PnvChip { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + uint32_t chip_id; + uint64_t ram_start; + uint64_t ram_size; + + uint32_t nr_cores; + uint32_t nr_threads; + uint64_t cores_mask; + PnvCore **cores; + + uint32_t num_pecs; + + MemoryRegion xscom_mmio; + MemoryRegion xscom; + AddressSpace xscom_as; + + MemoryRegion *fw_mr; + gchar *dt_isa_nodename; +}; + +#define TYPE_PNV8_CHIP "pnv8-chip" +DECLARE_INSTANCE_CHECKER(Pnv8Chip, PNV8_CHIP, + TYPE_PNV8_CHIP) + +struct Pnv8Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + MemoryRegion icp_mmio; + + PnvLpcController lpc; + Pnv8Psi psi; + PnvOCC occ; + PnvHomer homer; + +#define PNV8_CHIP_PHB3_MAX 4 + /* + * The array is used to allow quick access to the phbs by + * pnv_ics_get_child() and pnv_ics_resend_child(). + */ + PnvPHB *phbs[PNV8_CHIP_PHB3_MAX]; + uint32_t num_phbs; + + XICSFabric *xics; +}; + +#define TYPE_PNV9_CHIP "pnv9-chip" +DECLARE_INSTANCE_CHECKER(Pnv9Chip, PNV9_CHIP, + TYPE_PNV9_CHIP) + +struct Pnv9Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + PnvXive xive; + Pnv9Psi psi; + PnvLpcController lpc; + PnvOCC occ; + PnvSBE sbe; + PnvHomer homer; + + uint32_t nr_quads; + PnvQuad *quads; + +#define PNV9_CHIP_MAX_PEC 3 + PnvPhb4PecState pecs[PNV9_CHIP_MAX_PEC]; +}; + +/* + * A SMT8 fused core is a pair of SMT4 cores. + */ +#define PNV9_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf) +#define PNV9_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) + +#define TYPE_PNV10_CHIP "pnv10-chip" +DECLARE_INSTANCE_CHECKER(Pnv10Chip, PNV10_CHIP, + TYPE_PNV10_CHIP) + +struct Pnv10Chip { + /*< private >*/ + PnvChip parent_obj; + + /*< public >*/ + PnvXive2 xive; + Pnv9Psi psi; + PnvLpcController lpc; + PnvOCC occ; + PnvSBE sbe; + PnvHomer homer; + + uint32_t nr_quads; + PnvQuad *quads; + +#define PNV10_CHIP_MAX_PEC 2 + PnvPhb4PecState pecs[PNV10_CHIP_MAX_PEC]; +}; + +#define PNV10_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf) +#define PNV10_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) + +struct PnvChipClass { + /*< private >*/ + SysBusDeviceClass parent_class; + + /*< public >*/ + uint64_t chip_cfam_id; + uint64_t cores_mask; + uint32_t num_pecs; + uint32_t num_phbs; + + DeviceRealize parent_realize; + + uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id); + void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp); + void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu); + void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu); + void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, Monitor *mon); + ISABus *(*isa_create)(PnvChip *chip, Error **errp); + void (*dt_populate)(PnvChip *chip, void *fdt); + void (*pic_print_info)(PnvChip *chip, Monitor *mon); + uint64_t (*xscom_core_base)(PnvChip *chip, uint32_t core_id); + uint32_t (*xscom_pcba)(PnvChip *chip, uint64_t addr); +}; + +#endif From 14f11a204cdc2ccb44d82ebb6f9646becca0178a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 22 Dec 2022 11:46:26 +0100 Subject: [PATCH 168/814] include/hw/ppc: Supply a few missing includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few headers neglect to include headers they need. They compile only if something else includes the required header(s) first. Fix that. Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Reviewed-by: Daniel Henrique Barboza Message-Id: <20221222104628.659681-3-armbru@redhat.com> --- include/hw/ppc/pnv_lpc.h | 3 ++- include/hw/ppc/pnv_occ.h | 3 ++- include/hw/ppc/pnv_pnor.h | 2 +- include/hw/ppc/pnv_sbe.h | 3 ++- include/hw/ppc/pnv_xscom.h | 3 ++- include/hw/ppc/xive2.h | 2 ++ include/hw/ppc/xive2_regs.h | 2 ++ 7 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index 8a8d1a3d42..001eee27d7 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -20,7 +20,8 @@ #ifndef PPC_PNV_LPC_H #define PPC_PNV_LPC_H -#include "qom/object.h" +#include "exec/memory.h" +#include "hw/qdev-core.h" #define TYPE_PNV_LPC "pnv-lpc" typedef struct PnvLpcClass PnvLpcClass; diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index 90a81dae2b..df321244e3 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -20,7 +20,8 @@ #ifndef PPC_PNV_OCC_H #define PPC_PNV_OCC_H -#include "qom/object.h" +#include "exec/memory.h" +#include "hw/qdev-core.h" #define TYPE_PNV_OCC "pnv-occ" OBJECT_DECLARE_TYPE(PnvOCC, PnvOCCClass, diff --git a/include/hw/ppc/pnv_pnor.h b/include/hw/ppc/pnv_pnor.h index bab2f79844..2e37ac88bf 100644 --- a/include/hw/ppc/pnv_pnor.h +++ b/include/hw/ppc/pnv_pnor.h @@ -10,7 +10,7 @@ #ifndef PPC_PNV_PNOR_H #define PPC_PNV_PNOR_H -#include "qom/object.h" +#include "hw/sysbus.h" /* * PNOR offset on the LPC FW address space diff --git a/include/hw/ppc/pnv_sbe.h b/include/hw/ppc/pnv_sbe.h index f54a3ae9ba..b6b378ad14 100644 --- a/include/hw/ppc/pnv_sbe.h +++ b/include/hw/ppc/pnv_sbe.h @@ -20,7 +20,8 @@ #ifndef PPC_PNV_SBE_H #define PPC_PNV_SBE_H -#include "qom/object.h" +#include "exec/memory.h" +#include "hw/qdev-core.h" #define TYPE_PNV_SBE "pnv-sbe" OBJECT_DECLARE_TYPE(PnvSBE, PnvSBEClass, PNV_SBE) diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index c6e9ef8dd2..cbe848d27b 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -20,7 +20,8 @@ #ifndef PPC_PNV_XSCOM_H #define PPC_PNV_XSCOM_H -#include "qom/object.h" +#include "exec/memory.h" +#include "hw/ppc/pnv.h" typedef struct PnvXScomInterface PnvXScomInterface; diff --git a/include/hw/ppc/xive2.h b/include/hw/ppc/xive2.h index e9e3ea135e..ab68f8d157 100644 --- a/include/hw/ppc/xive2.h +++ b/include/hw/ppc/xive2.h @@ -11,7 +11,9 @@ #ifndef PPC_XIVE2_H #define PPC_XIVE2_H +#include "hw/ppc/xive.h" #include "hw/ppc/xive2_regs.h" +#include "hw/sysbus.h" /* * XIVE2 Router (POWER10) diff --git a/include/hw/ppc/xive2_regs.h b/include/hw/ppc/xive2_regs.h index 14605bd458..b7adbdb7b9 100644 --- a/include/hw/ppc/xive2_regs.h +++ b/include/hw/ppc/xive2_regs.h @@ -10,6 +10,8 @@ #ifndef PPC_XIVE2_REGS_H #define PPC_XIVE2_REGS_H +#include "cpu.h" + /* * Thread Interrupt Management Area (TIMA) * From c0a5a477f148d8cb8e47dda36601032a3f5aa991 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 22 Dec 2022 11:46:27 +0100 Subject: [PATCH 169/814] include/hw/ppc: Don't include hw/pci-host/pnv_phb.h from pnv.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The next commit needs to include hw/ppc/pnv.h from hw/pci-host/pnv_phb.h. Avoid an inclusion loop. Signed-off-by: Markus Armbruster Reviewed-by: Cédric Le Goater Reviewed-by: Daniel Henrique Barboza Message-Id: <20221222104628.659681-4-armbru@redhat.com> --- hw/ppc/pnv_psi.c | 1 + include/hw/pci-host/pnv_phb4.h | 3 ++- include/hw/ppc/pnv.h | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 98045ed3d2..8aa09ab26b 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "exec/address-spaces.h" #include "hw/irq.h" #include "target/ppc/cpu.h" #include "qemu/log.h" diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index d9cea3f952..b4f2b29fb5 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -10,14 +10,15 @@ #ifndef PCI_HOST_PNV_PHB4_H #define PCI_HOST_PNV_PHB4_H +#include "hw/pci-host/pnv_phb.h" #include "hw/pci/pci_bus.h" +#include "hw/ppc/pnv.h" #include "hw/ppc/xive.h" #include "qom/object.h" typedef struct PnvPhb4PecState PnvPhb4PecState; typedef struct PnvPhb4PecStack PnvPhb4PecStack; typedef struct PnvPHB4 PnvPHB4; -typedef struct PnvPHB PnvPHB; typedef struct PnvChip PnvChip; /* diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index ca49e4281d..96fb850419 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -25,7 +25,6 @@ #include "hw/sysbus.h" #include "hw/ipmi/ipmi.h" #include "hw/ppc/pnv_pnor.h" -#include "hw/pci-host/pnv_phb.h" #define TYPE_PNV_CHIP "pnv-chip" @@ -59,6 +58,8 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10, PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir); +typedef struct PnvPHB PnvPHB; + #define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") typedef struct PnvMachineClass PnvMachineClass; typedef struct PnvMachineState PnvMachineState; From b6c80037ed3ba275eea2b33bc17e36af2b89813a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 22 Dec 2022 11:46:28 +0100 Subject: [PATCH 170/814] include/hw/ppc include/hw/pci-host: Drop extra typedefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PnvChip is typedef'ed in five places, and PnvPhb4PecState in two. Keep one, drop the others. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Daniel Henrique Barboza Message-Id: <20221222104628.659681-5-armbru@redhat.com> --- hw/pci-host/pnv_phb.h | 2 +- include/hw/pci-host/pnv_phb3.h | 1 - include/hw/pci-host/pnv_phb4.h | 2 -- include/hw/ppc/pnv_core.h | 3 +-- include/hw/ppc/pnv_homer.h | 2 +- include/hw/ppc/pnv_lpc.h | 8 ++------ include/hw/ppc/pnv_xive.h | 7 +++---- 7 files changed, 8 insertions(+), 17 deletions(-) diff --git a/hw/pci-host/pnv_phb.h b/hw/pci-host/pnv_phb.h index 58ebd6dd0f..eb429d529f 100644 --- a/hw/pci-host/pnv_phb.h +++ b/hw/pci-host/pnv_phb.h @@ -12,9 +12,9 @@ #include "hw/pci/pcie_host.h" #include "hw/pci/pcie_port.h" +#include "hw/ppc/pnv.h" #include "qom/object.h" -typedef struct PnvChip PnvChip; typedef struct PnvPhb4PecState PnvPhb4PecState; struct PnvPHB { diff --git a/include/hw/pci-host/pnv_phb3.h b/include/hw/pci-host/pnv_phb3.h index f791ebda9b..d62b3091ac 100644 --- a/include/hw/pci-host/pnv_phb3.h +++ b/include/hw/pci-host/pnv_phb3.h @@ -15,7 +15,6 @@ #include "hw/pci-host/pnv_phb.h" typedef struct PnvPHB3 PnvPHB3; -typedef struct PnvChip PnvChip; /* * PHB3 XICS Source for MSIs diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index b4f2b29fb5..1f3237c9d5 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -16,10 +16,8 @@ #include "hw/ppc/xive.h" #include "qom/object.h" -typedef struct PnvPhb4PecState PnvPhb4PecState; typedef struct PnvPhb4PecStack PnvPhb4PecStack; typedef struct PnvPHB4 PnvPHB4; -typedef struct PnvChip PnvChip; /* * We have one such address space wrapper per possible device under diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h index c22eab2e1f..3d75706e95 100644 --- a/include/hw/ppc/pnv_core.h +++ b/include/hw/ppc/pnv_core.h @@ -22,14 +22,13 @@ #include "hw/cpu/core.h" #include "target/ppc/cpu.h" +#include "hw/ppc/pnv.h" #include "qom/object.h" #define TYPE_PNV_CORE "powernv-cpu-core" OBJECT_DECLARE_TYPE(PnvCore, PnvCoreClass, PNV_CORE) -typedef struct PnvChip PnvChip; - struct PnvCore { /*< private >*/ CPUCore parent_obj; diff --git a/include/hw/ppc/pnv_homer.h b/include/hw/ppc/pnv_homer.h index 07e8b19311..b1c5d498dc 100644 --- a/include/hw/ppc/pnv_homer.h +++ b/include/hw/ppc/pnv_homer.h @@ -39,7 +39,7 @@ DECLARE_INSTANCE_CHECKER(PnvHomer, PNV10_HOMER, struct PnvHomer { DeviceState parent; - struct PnvChip *chip; + PnvChip *chip; MemoryRegion pba_regs; MemoryRegion regs; }; diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index 001eee27d7..5d22c45570 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -21,6 +21,7 @@ #define PPC_PNV_LPC_H #include "exec/memory.h" +#include "hw/ppc/pnv.h" #include "hw/qdev-core.h" #define TYPE_PNV_LPC "pnv-lpc" @@ -93,13 +94,8 @@ struct PnvLpcClass { DeviceRealize parent_realize; }; -/* - * Old compilers error on typdef forward declarations. Keep them happy. - */ -struct PnvChip; - ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp); -int pnv_dt_lpc(struct PnvChip *chip, void *fdt, int root_offset, +int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset, uint64_t lpcm_addr, uint64_t lpcm_size); #endif /* PPC_PNV_LPC_H */ diff --git a/include/hw/ppc/pnv_xive.h b/include/hw/ppc/pnv_xive.h index b5d91505e5..9c48430ee4 100644 --- a/include/hw/ppc/pnv_xive.h +++ b/include/hw/ppc/pnv_xive.h @@ -10,12 +10,11 @@ #ifndef PPC_PNV_XIVE_H #define PPC_PNV_XIVE_H +#include "hw/ppc/pnv.h" #include "hw/ppc/xive.h" #include "qom/object.h" #include "hw/ppc/xive2.h" -struct PnvChip; - #define TYPE_PNV_XIVE "pnv-xive" OBJECT_DECLARE_TYPE(PnvXive, PnvXiveClass, PNV_XIVE) @@ -31,7 +30,7 @@ struct PnvXive { XiveRouter parent_obj; /* Owning chip */ - struct PnvChip *chip; + PnvChip *chip; /* XSCOM addresses giving access to the controller registers */ MemoryRegion xscom_regs; @@ -106,7 +105,7 @@ typedef struct PnvXive2 { Xive2Router parent_obj; /* Owning chip */ - struct PnvChip *chip; + PnvChip *chip; /* XSCOM addresses giving access to the controller registers */ MemoryRegion xscom_regs; From bb461330a1ca4d90c67054b493ed408fb7852d74 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 15 Jan 2023 07:16:33 -1000 Subject: [PATCH 171/814] target/arm: Widen cnthctl_el2 to uint64_t This is a 64-bit register on AArch64, even if the high 44 bits are RES0. Because this is defined as ARM_CP_STATE_BOTH, we are asserting that the cpreg field is 64-bits. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1400 Signed-off-by: Richard Henderson Message-id: 20230115171633.3171890-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index bf2bce046d..1feb63b4d7 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -479,7 +479,7 @@ typedef struct CPUArchState { }; uint64_t c14_cntfrq; /* Counter Frequency register */ uint64_t c14_cntkctl; /* Timer Control register */ - uint32_t cnthctl_el2; /* Counter/Timer Hyp Control register */ + uint64_t cnthctl_el2; /* Counter/Timer Hyp Control register */ uint64_t cntvoff_el2; /* Counter Virtual Offset register */ ARMGenericTimer c14_timer[NUM_GTIMERS]; uint32_t c15_cpar; /* XScale Coprocessor Access Register */ From 0ec69c460ef7a02596afbe4bd46c9fa954a5f992 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Mon, 9 Jan 2023 15:05:19 -0800 Subject: [PATCH 172/814] target/arm: Unify checking for M Main Extension in MRS/MSR BASEPRI, FAULTMASK, and their _NS equivalents only exist on devices with the Main Extension. However, the MRS instruction did not check this, and the MSR instruction handled it inconsistently (warning BASEPRI, but silently ignoring writes to BASEPRI_NS). Unify this behavior and always warn when reading or writing any of these registers if the extension is not present. Signed-off-by: David Reiss Message-id: 167330628518.10497.13100425787268927786-0@git.sr.ht Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/m_helper.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 033a4d9261..d87b9ecd12 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -2465,11 +2465,17 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) } return env->v7m.primask[M_REG_NS]; case 0x91: /* BASEPRI_NS */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } if (!env->v7m.secure) { return 0; } return env->v7m.basepri[M_REG_NS]; case 0x93: /* FAULTMASK_NS */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } if (!env->v7m.secure) { return 0; } @@ -2515,8 +2521,14 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) return env->v7m.primask[env->v7m.secure]; case 17: /* BASEPRI */ case 18: /* BASEPRI_MAX */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } return env->v7m.basepri[env->v7m.secure]; case 19: /* FAULTMASK */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } return env->v7m.faultmask[env->v7m.secure]; default: bad_reg: @@ -2581,13 +2593,19 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.primask[M_REG_NS] = val & 1; return; case 0x91: /* BASEPRI_NS */ - if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) { + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } + if (!env->v7m.secure) { return; } env->v7m.basepri[M_REG_NS] = val & 0xff; return; case 0x93: /* FAULTMASK_NS */ - if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) { + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } + if (!env->v7m.secure) { return; } env->v7m.faultmask[M_REG_NS] = val & 1; From da8df26d2ea7eb1bfd6cc7fec37aabf6137f385d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 09:50:12 +0100 Subject: [PATCH 173/814] hw/i2c/bitbang_i2c: Define TYPE_GPIO_I2C in public header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define TYPE_GPIO_I2C in the public "hw/i2c/bitbang_i2c.h" header and use it in hw/arm/musicpal.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Acked-by: Corey Minyard Message-id: 20230111085016.44551-2-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/arm/musicpal.c | 3 ++- hw/i2c/bitbang_i2c.c | 1 - include/hw/i2c/bitbang_i2c.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 73e2b7e4ce..89b66606c3 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -26,6 +26,7 @@ #include "hw/block/flash.h" #include "ui/console.h" #include "hw/i2c/i2c.h" +#include "hw/i2c/bitbang_i2c.h" #include "hw/irq.h" #include "hw/or-irq.h" #include "hw/audio/wm8750.h" @@ -1303,7 +1304,7 @@ static void musicpal_init(MachineState *machine) dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE, qdev_get_gpio_in(pic, MP_GPIO_IRQ)); - i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); + i2c_dev = sysbus_create_simple(TYPE_GPIO_I2C, -1, NULL); i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"); lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL); diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index e9a0612a04..ac84bf0262 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -162,7 +162,6 @@ void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus) /* GPIO interface. */ -#define TYPE_GPIO_I2C "gpio_i2c" OBJECT_DECLARE_SIMPLE_TYPE(GPIOI2CState, GPIO_I2C) struct GPIOI2CState { diff --git a/include/hw/i2c/bitbang_i2c.h b/include/hw/i2c/bitbang_i2c.h index 92334e9016..a079e6d70f 100644 --- a/include/hw/i2c/bitbang_i2c.h +++ b/include/hw/i2c/bitbang_i2c.h @@ -3,6 +3,8 @@ #include "hw/i2c/i2c.h" +#define TYPE_GPIO_I2C "gpio_i2c" + typedef struct bitbang_i2c_interface bitbang_i2c_interface; #define BITBANG_I2C_SDA 0 From 2b9339d3b4642f57fafac2a2312bda68377da740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 09:50:13 +0100 Subject: [PATCH 174/814] hw/i2c/bitbang_i2c: Remove unused dummy MemoryRegion 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 Acked-by: Corey Minyard Message-id: 20230111085016.44551-3-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/bitbang_i2c.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index ac84bf0262..e41cb63daa 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -165,9 +165,10 @@ void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus) OBJECT_DECLARE_SIMPLE_TYPE(GPIOI2CState, GPIO_I2C) struct GPIOI2CState { + /*< private >*/ SysBusDevice parent_obj; + /*< public >*/ - MemoryRegion dummy_iomem; bitbang_i2c_interface bitbang; int last_level; qemu_irq out; @@ -188,12 +189,8 @@ static void gpio_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); GPIOI2CState *s = GPIO_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); I2CBus *bus; - memory_region_init(&s->dummy_iomem, obj, "gpio_i2c", 0); - sysbus_init_mmio(sbd, &s->dummy_iomem); - bus = i2c_init_bus(dev, "i2c"); bitbang_i2c_init(&s->bitbang, bus); From dc575b5e0300a7a375b4e4501a17ada21e9a6d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 09:50:14 +0100 Subject: [PATCH 175/814] hw/i2c/bitbang_i2c: Change state calling bitbang_i2c_set_state() helper 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 Acked-by: Corey Minyard Message-id: 20230111085016.44551-4-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/bitbang_i2c.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index e41cb63daa..bf4b781393 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -26,13 +26,19 @@ do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif +static void bitbang_i2c_set_state(bitbang_i2c_interface *i2c, + bitbang_i2c_state state) +{ + i2c->state = state; +} + static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) { DPRINTF("STOP\n"); if (i2c->current_addr >= 0) i2c_end_transfer(i2c->bus); i2c->current_addr = -1; - i2c->state = STOPPED; + bitbang_i2c_set_state(i2c, STOPPED); } /* Set device data pin. */ @@ -69,7 +75,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) if (level == 0) { DPRINTF("START\n"); /* START condition. */ - i2c->state = SENDING_BIT7; + bitbang_i2c_set_state(i2c, SENDING_BIT7); i2c->current_addr = -1; } else { /* STOP condition. */ @@ -96,7 +102,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) case SENDING_BIT7 ... SENDING_BIT0: i2c->buffer = (i2c->buffer << 1) | data; /* will end up in WAITING_FOR_ACK */ - i2c->state++; + bitbang_i2c_set_state(i2c, i2c->state + 1); return bitbang_i2c_ret(i2c, 1); case WAITING_FOR_ACK: @@ -117,13 +123,14 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) * device we were sending to decided to NACK us). */ DPRINTF("Got NACK\n"); + bitbang_i2c_set_state(i2c, SENT_NACK); bitbang_i2c_enter_stop(i2c); return bitbang_i2c_ret(i2c, 1); } if (i2c->current_addr & 1) { - i2c->state = RECEIVING_BIT7; + bitbang_i2c_set_state(i2c, RECEIVING_BIT7); } else { - i2c->state = SENDING_BIT7; + bitbang_i2c_set_state(i2c, SENDING_BIT7); } return bitbang_i2c_ret(i2c, 0); } @@ -134,18 +141,18 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) case RECEIVING_BIT6 ... RECEIVING_BIT0: data = i2c->buffer >> 7; /* will end up in SENDING_ACK */ - i2c->state++; + bitbang_i2c_set_state(i2c, i2c->state + 1); i2c->buffer <<= 1; return bitbang_i2c_ret(i2c, data); case SENDING_ACK: - i2c->state = RECEIVING_BIT7; if (data != 0) { DPRINTF("NACKED\n"); - i2c->state = SENT_NACK; + bitbang_i2c_set_state(i2c, SENT_NACK); i2c_nack(i2c->bus); } else { DPRINTF("ACKED\n"); + bitbang_i2c_set_state(i2c, RECEIVING_BIT7); } return bitbang_i2c_ret(i2c, 1); } From 1e5b1899ccea8b69e3393c7ed2040aef8b33a9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 09:50:15 +0100 Subject: [PATCH 176/814] hw/i2c/bitbang_i2c: Trace state changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trace bitbang state machine changes with trace events. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Acked-by: Corey Minyard Message-id: 20230111085016.44551-5-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/bitbang_i2c.c | 33 ++++++++++++++++++++++++++++----- hw/i2c/trace-events | 3 +++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index bf4b781393..efc49b7502 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -16,6 +16,7 @@ #include "hw/sysbus.h" #include "qemu/module.h" #include "qom/object.h" +#include "trace.h" //#define DEBUG_BITBANG_I2C @@ -26,15 +27,41 @@ do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif +/* bitbang_i2c_state enum to name */ +static const char * const sname[] = { +#define NAME(e) [e] = stringify(e) + NAME(STOPPED), + [SENDING_BIT7] = "SENDING_BIT7 (START)", + NAME(SENDING_BIT6), + NAME(SENDING_BIT5), + NAME(SENDING_BIT4), + NAME(SENDING_BIT3), + NAME(SENDING_BIT2), + NAME(SENDING_BIT1), + NAME(SENDING_BIT0), + NAME(WAITING_FOR_ACK), + [RECEIVING_BIT7] = "RECEIVING_BIT7 (ACK)", + NAME(RECEIVING_BIT6), + NAME(RECEIVING_BIT5), + NAME(RECEIVING_BIT4), + NAME(RECEIVING_BIT3), + NAME(RECEIVING_BIT2), + NAME(RECEIVING_BIT1), + NAME(RECEIVING_BIT0), + NAME(SENDING_ACK), + NAME(SENT_NACK) +#undef NAME +}; + static void bitbang_i2c_set_state(bitbang_i2c_interface *i2c, bitbang_i2c_state state) { + trace_bitbang_i2c_state(sname[i2c->state], sname[state]); i2c->state = state; } static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) { - DPRINTF("STOP\n"); if (i2c->current_addr >= 0) i2c_end_transfer(i2c->bus); i2c->current_addr = -1; @@ -73,7 +100,6 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) return bitbang_i2c_nop(i2c); } if (level == 0) { - DPRINTF("START\n"); /* START condition. */ bitbang_i2c_set_state(i2c, SENDING_BIT7); i2c->current_addr = -1; @@ -122,7 +148,6 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) /* NACK (either addressing a nonexistent device, or the * device we were sending to decided to NACK us). */ - DPRINTF("Got NACK\n"); bitbang_i2c_set_state(i2c, SENT_NACK); bitbang_i2c_enter_stop(i2c); return bitbang_i2c_ret(i2c, 1); @@ -147,11 +172,9 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) case SENDING_ACK: if (data != 0) { - DPRINTF("NACKED\n"); bitbang_i2c_set_state(i2c, SENT_NACK); i2c_nack(i2c->bus); } else { - DPRINTF("ACKED\n"); bitbang_i2c_set_state(i2c, RECEIVING_BIT7); } return bitbang_i2c_ret(i2c, 1); diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 52dbd53a23..48aee4887c 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -1,5 +1,8 @@ # See docs/devel/tracing.rst for syntax documentation. +# bitbang_i2c.c +bitbang_i2c_state(const char *old_state, const char *new_state) "state %s -> %s" + # core.c i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)" From c166e592a7457e0ac3398cd14ba543bce032c88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 09:50:16 +0100 Subject: [PATCH 177/814] hw/i2c/bitbang_i2c: Convert DPRINTF() to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the remaining DPRINTF debug macro uses to tracepoints. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Acked-by: Corey Minyard Message-id: 20230111085016.44551-6-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/bitbang_i2c.c | 18 ++++++------------ hw/i2c/trace-events | 4 ++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index efc49b7502..bb18954765 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -18,14 +18,6 @@ #include "qom/object.h" #include "trace.h" -//#define DEBUG_BITBANG_I2C - -#ifdef DEBUG_BITBANG_I2C -#define DPRINTF(fmt, ...) \ -do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif /* bitbang_i2c_state enum to name */ static const char * const sname[] = { @@ -71,8 +63,10 @@ static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) /* Set device data pin. */ static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level) { + trace_bitbang_i2c_data(i2c->last_clock, i2c->last_data, + i2c->device_out, level); i2c->device_out = level; - //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out); + return level & i2c->last_data; } @@ -137,11 +131,11 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) if (i2c->current_addr < 0) { i2c->current_addr = i2c->buffer; - DPRINTF("Address 0x%02x\n", i2c->current_addr); + trace_bitbang_i2c_addr(i2c->current_addr); ret = i2c_start_transfer(i2c->bus, i2c->current_addr >> 1, i2c->current_addr & 1); } else { - DPRINTF("Sent 0x%02x\n", i2c->buffer); + trace_bitbang_i2c_send(i2c->buffer); ret = i2c_send(i2c->bus, i2c->buffer); } if (ret) { @@ -161,7 +155,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) } case RECEIVING_BIT7: i2c->buffer = i2c_recv(i2c->bus); - DPRINTF("RX byte 0x%02x\n", i2c->buffer); + trace_bitbang_i2c_recv(i2c->buffer); /* Fall through... */ case RECEIVING_BIT6 ... RECEIVING_BIT0: data = i2c->buffer >> 7; diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 48aee4887c..8e88aa24c1 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -2,6 +2,10 @@ # bitbang_i2c.c bitbang_i2c_state(const char *old_state, const char *new_state) "state %s -> %s" +bitbang_i2c_addr(uint8_t addr) "Address 0x%02x" +bitbang_i2c_send(uint8_t byte) "TX byte 0x%02x" +bitbang_i2c_recv(uint8_t byte) "RX byte 0x%02x" +bitbang_i2c_data(unsigned dat, unsigned clk, unsigned old_out, unsigned new_out) "dat %u clk %u out %u -> %u" # core.c From 280b9ecbc5f85a5b936091580c9096bf0c248da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 09:25:04 +0100 Subject: [PATCH 178/814] hw/i2c/versatile_i2c: Drop useless casts from void * to pointer 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: 20230110082508.24038-2-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 3a04ba3969..52a650f45e 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -45,7 +45,7 @@ REG32(CONTROL_CLR, 4) static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { - VersatileI2CState *s = (VersatileI2CState *)opaque; + VersatileI2CState *s = opaque; switch (offset) { case A_CONTROL_SET: @@ -60,7 +60,7 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, static void versatile_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - VersatileI2CState *s = (VersatileI2CState *)opaque; + VersatileI2CState *s = opaque; switch (offset) { case A_CONTROL_SET: From 92518611acef9c44b215a784c71c5766e3ca6fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 09:25:05 +0100 Subject: [PATCH 179/814] hw/i2c/versatile_i2c: Replace VersatileI2CState -> ArmSbconI2CState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to rename TYPE_VERSATILE_I2C as TYPE_ARM_SBCON_I2C (the formal ARM naming), start renaming its state. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230110082508.24038-3-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 10 +++++----- include/hw/i2c/arm_sbcon_i2c.h | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 52a650f45e..ee095762e5 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -30,7 +30,7 @@ #include "qom/object.h" typedef ArmSbconI2CState VersatileI2CState; -DECLARE_INSTANCE_CHECKER(VersatileI2CState, VERSATILE_I2C, +DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, VERSATILE_I2C, TYPE_VERSATILE_I2C) @@ -45,7 +45,7 @@ REG32(CONTROL_CLR, 4) static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { - VersatileI2CState *s = opaque; + ArmSbconI2CState *s = opaque; switch (offset) { case A_CONTROL_SET: @@ -60,7 +60,7 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, static void versatile_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - VersatileI2CState *s = opaque; + ArmSbconI2CState *s = opaque; switch (offset) { case A_CONTROL_SET: @@ -86,7 +86,7 @@ static const MemoryRegionOps versatile_i2c_ops = { static void versatile_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); - VersatileI2CState *s = VERSATILE_I2C(obj); + ArmSbconI2CState *s = VERSATILE_I2C(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); I2CBus *bus; @@ -100,7 +100,7 @@ static void versatile_i2c_init(Object *obj) static const TypeInfo versatile_i2c_info = { .name = TYPE_VERSATILE_I2C, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VersatileI2CState), + .instance_size = sizeof(ArmSbconI2CState), .instance_init = versatile_i2c_init, }; diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h index f54d1e5413..0101422d9d 100644 --- a/include/hw/i2c/arm_sbcon_i2c.h +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -21,8 +21,7 @@ #define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C typedef struct ArmSbconI2CState ArmSbconI2CState; -DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, - TYPE_ARM_SBCON_I2C) +DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C) struct ArmSbconI2CState { /*< private >*/ From 550da1cc22c49f0df427232be29484230d15029b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 09:25:06 +0100 Subject: [PATCH 180/814] hw/i2c/versatile_i2c: Replace TYPE_VERSATILE_I2C -> TYPE_ARM_SBCON_I2C 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: 20230110082508.24038-4-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/arm/realview.c | 2 +- hw/arm/versatilepb.c | 2 +- hw/arm/vexpress.c | 2 +- hw/i2c/versatile_i2c.c | 4 ++-- include/hw/i2c/arm_sbcon_i2c.h | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index d2dc8a8952..a5aa2f046a 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -309,7 +309,7 @@ static void realview_init(MachineState *machine, } } - dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_slave_create_simple(i2c, "ds1338", 0x68); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 43172d72ea..05b9462a5b 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -336,7 +336,7 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL031 Real Time Clock. */ sysbus_create_simple("pl031", 0x101e8000, pic[10]); - dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_slave_create_simple(i2c, "ds1338", 0x68); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 757236767b..34b012b528 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -646,7 +646,7 @@ static void vexpress_common_init(MachineState *machine) sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); - dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL); + dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, map[VE_SERIALDVI], NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_slave_create_simple(i2c, "sii9022", 0x39); diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index ee095762e5..b95c70608b 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -31,7 +31,7 @@ typedef ArmSbconI2CState VersatileI2CState; DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, VERSATILE_I2C, - TYPE_VERSATILE_I2C) + TYPE_ARM_SBCON_I2C) @@ -98,7 +98,7 @@ static void versatile_i2c_init(Object *obj) } static const TypeInfo versatile_i2c_info = { - .name = TYPE_VERSATILE_I2C, + .name = TYPE_ARM_SBCON_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ArmSbconI2CState), .instance_init = versatile_i2c_init, diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h index 0101422d9d..da9b5e8f83 100644 --- a/include/hw/i2c/arm_sbcon_i2c.h +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -17,8 +17,7 @@ #include "hw/i2c/bitbang_i2c.h" #include "qom/object.h" -#define TYPE_VERSATILE_I2C "versatile_i2c" -#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C +#define TYPE_ARM_SBCON_I2C "versatile_i2c" typedef struct ArmSbconI2CState ArmSbconI2CState; DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C) From f6cf2eb8ec6d2d2e3e5fd51147079228c65833bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 09:25:07 +0100 Subject: [PATCH 181/814] hw/i2c/versatile_i2c: Use ARM_SBCON_I2C() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM_SBCON_I2C() macro and ArmSbconI2CState typedef are already declared via the QOM DECLARE_INSTANCE_CHECKER() macro in "hw/i2c/arm_sbcon_i2c.h". Drop the VERSATILE_I2C declarations from versatile_i2c.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230110082508.24038-5-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index b95c70608b..d19df62265 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -29,11 +29,6 @@ #include "qemu/module.h" #include "qom/object.h" -typedef ArmSbconI2CState VersatileI2CState; -DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, VERSATILE_I2C, - TYPE_ARM_SBCON_I2C) - - REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) @@ -86,7 +81,7 @@ static const MemoryRegionOps versatile_i2c_ops = { static void versatile_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); - ArmSbconI2CState *s = VERSATILE_I2C(obj); + ArmSbconI2CState *s = ARM_SBCON_I2C(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); I2CBus *bus; From 500a64d82b4cb533bcacaaadcf998c906e52a80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 10 Jan 2023 09:25:08 +0100 Subject: [PATCH 182/814] hw/i2c/versatile_i2c: Rename versatile_i2c -> arm_sbcon_i2c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This device model started with the Versatile board, named TYPE_VERSATILE_I2C, then ended up renamed TYPE_ARM_SBCON_I2C as per the official "ARM SBCon two-wire serial bus interface" description from: https://developer.arm.com/documentation/dui0440/b/programmer-s-reference/two-wire-serial-bus-interface--sbcon Use the latter name as a better description. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230110082508.24038-6-philmd@linaro.org Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + hw/arm/Kconfig | 4 ++-- hw/i2c/Kconfig | 2 +- hw/i2c/{versatile_i2c.c => arm_sbcon_i2c.c} | 24 ++++++++++----------- hw/i2c/meson.build | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) rename hw/i2c/{versatile_i2c.c => arm_sbcon_i2c.c} (81%) diff --git a/MAINTAINERS b/MAINTAINERS index 08ad1e5341..c581c11a64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -942,6 +942,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/*/versatile* +F: hw/i2c/arm_sbcon_i2c.c F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c F: docs/system/arm/versatile.rst diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 19d6b9d95f..2d157de9b8 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -211,7 +211,7 @@ config REALVIEW select PL110 select PL181 # display select PL310 # cache controller - select VERSATILE_I2C + select ARM_SBCON_I2C select DS1338 # I2C RTC+NVRAM select USB_OHCI @@ -481,7 +481,7 @@ config MPS2 select SPLIT_IRQ select UNIMP select CMSDK_APB_WATCHDOG - select VERSATILE_I2C + select ARM_SBCON_I2C config FSL_IMX7 bool diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index f8ec461be3..14886b35da 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -14,7 +14,7 @@ config SMBUS_EEPROM bool select SMBUS -config VERSATILE_I2C +config ARM_SBCON_I2C bool select BITBANG_I2C diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/arm_sbcon_i2c.c similarity index 81% rename from hw/i2c/versatile_i2c.c rename to hw/i2c/arm_sbcon_i2c.c index d19df62265..979ccbe0ed 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/arm_sbcon_i2c.c @@ -37,7 +37,7 @@ REG32(CONTROL_CLR, 4) #define SCL BIT(0) #define SDA BIT(1) -static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, +static uint64_t arm_sbcon_i2c_read(void *opaque, hwaddr offset, unsigned size) { ArmSbconI2CState *s = opaque; @@ -52,7 +52,7 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, } } -static void versatile_i2c_write(void *opaque, hwaddr offset, +static void arm_sbcon_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { ArmSbconI2CState *s = opaque; @@ -72,13 +72,13 @@ static void versatile_i2c_write(void *opaque, hwaddr offset, s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0); } -static const MemoryRegionOps versatile_i2c_ops = { - .read = versatile_i2c_read, - .write = versatile_i2c_write, +static const MemoryRegionOps arm_sbcon_i2c_ops = { + .read = arm_sbcon_i2c_read, + .write = arm_sbcon_i2c_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void versatile_i2c_init(Object *obj) +static void arm_sbcon_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); ArmSbconI2CState *s = ARM_SBCON_I2C(obj); @@ -87,21 +87,21 @@ static void versatile_i2c_init(Object *obj) bus = i2c_init_bus(dev, "i2c"); bitbang_i2c_init(&s->bitbang, bus); - memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s, + memory_region_init_io(&s->iomem, obj, &arm_sbcon_i2c_ops, s, "arm_sbcon_i2c", 0x1000); sysbus_init_mmio(sbd, &s->iomem); } -static const TypeInfo versatile_i2c_info = { +static const TypeInfo arm_sbcon_i2c_info = { .name = TYPE_ARM_SBCON_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ArmSbconI2CState), - .instance_init = versatile_i2c_init, + .instance_init = arm_sbcon_i2c_init, }; -static void versatile_i2c_register_types(void) +static void arm_sbcon_i2c_register_types(void) { - type_register_static(&versatile_i2c_info); + type_register_static(&arm_sbcon_i2c_info); } -type_init(versatile_i2c_register_types) +type_init(arm_sbcon_i2c_register_types) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index e4c8e14a52..3996564c25 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -12,7 +12,7 @@ i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c')) i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c')) i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c')) i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c')) -i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c')) +i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c')) i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) From 535ca76425fc1ffa4311b3a47518b06c596a55c6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:30 +0100 Subject: [PATCH 183/814] target/arm/sme: Reorg SME access handling in handle_msr_i() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-2-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2ee171f249..35cc851246 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1841,18 +1841,20 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, goto do_unallocated; } if (sme_access_check(s)) { - bool i = crm & 1; - bool changed = false; + int old = s->pstate_sm | (s->pstate_za << 1); + int new = (crm & 1) * 3; + int msk = (crm >> 1) & 3; - if ((crm & 2) && i != s->pstate_sm) { - gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i)); - changed = true; - } - if ((crm & 4) && i != s->pstate_za) { - gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i)); - changed = true; - } - if (changed) { + if ((old ^ new) & msk) { + /* At least one bit changes. */ + bool i = crm & 1; + + if ((crm & 2) && i != s->pstate_sm) { + gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i)); + } + if ((crm & 4) && i != s->pstate_za) { + gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i)); + } gen_rebuild_hflags(s); } else { s->base.is_jmp = DISAS_NEXT; From 3c9ee548948870c14235e3fa8fb235c0c1c20822 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:31 +0100 Subject: [PATCH 184/814] target/arm/sme: Rebuild hflags in set_pstate() helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-3-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/sme_helper.c | 2 ++ target/arm/translate-a64.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index f891306bb9..b5aefa3eda 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -45,6 +45,7 @@ void helper_set_pstate_sm(CPUARMState *env, uint32_t i) } env->svcr ^= R_SVCR_SM_MASK; arm_reset_sve_state(env); + arm_rebuild_hflags(env); } void helper_set_pstate_za(CPUARMState *env, uint32_t i) @@ -65,6 +66,7 @@ void helper_set_pstate_za(CPUARMState *env, uint32_t i) if (i) { memset(env->zarray, 0, sizeof(env->zarray)); } + arm_rebuild_hflags(env); } void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 35cc851246..035e63bdc5 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1855,7 +1855,6 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, if ((crm & 4) && i != s->pstate_za) { gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i)); } - gen_rebuild_hflags(s); } else { s->base.is_jmp = DISAS_NEXT; } From 2a8af3825958e5d8c98b3ca92ac42a10e25db9e1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:32 +0100 Subject: [PATCH 185/814] target/arm/sme: Introduce aarch64_set_svcr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-4-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- linux-user/aarch64/cpu_loop.c | 2 +- linux-user/aarch64/signal.c | 2 +- target/arm/cpu.h | 1 + target/arm/helper.c | 8 ++++++++ target/arm/sme_helper.c | 4 ++-- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 9875d609a9..d53742e10b 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -93,8 +93,8 @@ void cpu_loop(CPUARMState *env) * On syscall, PSTATE.ZA is preserved, along with the ZA matrix. * PSTATE.SM is cleared, per SMSTOP, which does ResetSVEState. */ + aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); if (FIELD_EX64(env->svcr, SVCR, SM)) { - env->svcr = FIELD_DP64(env->svcr, SVCR, SM, 0); arm_rebuild_hflags(env); arm_reset_sve_state(env); } diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 6a2c6e06d2..b6e4dcb494 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -669,11 +669,11 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, * Invoke the signal handler with both SM and ZA disabled. * When clearing SM, ResetSVEState, per SMSTOP. */ + aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); if (FIELD_EX64(env->svcr, SVCR, SM)) { arm_reset_sve_state(env); } if (env->svcr) { - env->svcr = 0; arm_rebuild_hflags(env); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 1feb63b4d7..ef61849eb1 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1123,6 +1123,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el, bool el0_a64); +void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask); void arm_reset_sve_state(CPUARMState *env); /* diff --git a/target/arm/helper.c b/target/arm/helper.c index 22ea8fbe36..24c069b8ac 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6725,11 +6725,19 @@ static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) +{ + uint64_t change = (env->svcr ^ new) & mask; + + env->svcr ^= change; +} + static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM)); helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA)); + aarch64_set_svcr(env, value, -1); arm_rebuild_hflags(env); } diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index b5aefa3eda..94dc084135 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -43,7 +43,7 @@ void helper_set_pstate_sm(CPUARMState *env, uint32_t i) if (i == FIELD_EX64(env->svcr, SVCR, SM)) { return; } - env->svcr ^= R_SVCR_SM_MASK; + aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); arm_reset_sve_state(env); arm_rebuild_hflags(env); } @@ -53,7 +53,7 @@ void helper_set_pstate_za(CPUARMState *env, uint32_t i) if (i == FIELD_EX64(env->svcr, SVCR, ZA)) { return; } - env->svcr ^= R_SVCR_ZA_MASK; + aarch64_set_svcr(env, 0, R_SVCR_ZA_MASK); /* * ResetSMEState. From 7f2a01e7368f960fadea38f437d0f6de7f249686 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:33 +0100 Subject: [PATCH 186/814] target/arm/sme: Reset SVE state in aarch64_set_svcr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move arm_reset_sve_state() calls to aarch64_set_svcr(). Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-5-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- linux-user/aarch64/cpu_loop.c | 1 - linux-user/aarch64/signal.c | 8 +------- target/arm/cpu.h | 1 - target/arm/helper.c | 13 +++++++++++++ target/arm/sme_helper.c | 10 ---------- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index d53742e10b..5e93d27d8f 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -96,7 +96,6 @@ void cpu_loop(CPUARMState *env) aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); if (FIELD_EX64(env->svcr, SVCR, SM)) { arm_rebuild_hflags(env); - arm_reset_sve_state(env); } ret = do_syscall(env, env->xregs[8], diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index b6e4dcb494..a326a6def5 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -665,14 +665,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, env->btype = 2; } - /* - * Invoke the signal handler with both SM and ZA disabled. - * When clearing SM, ResetSVEState, per SMSTOP. - */ + /* Invoke the signal handler with both SM and ZA disabled. */ aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); - if (FIELD_EX64(env->svcr, SVCR, SM)) { - arm_reset_sve_state(env); - } if (env->svcr) { arm_rebuild_hflags(env); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ef61849eb1..f3ddc3b779 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1124,7 +1124,6 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el, bool el0_a64); void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask); -void arm_reset_sve_state(CPUARMState *env); /* * SVE registers are encoded in KVM's memory in an endianness-invariant format. diff --git a/target/arm/helper.c b/target/arm/helper.c index 24c069b8ac..0ac867c411 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6725,11 +6725,24 @@ static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* ResetSVEState */ +static void arm_reset_sve_state(CPUARMState *env) +{ + memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs)); + /* Recall that FFR is stored as pregs[16]. */ + memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs)); + vfp_set_fpcr(env, 0x0800009f); +} + void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) { uint64_t change = (env->svcr ^ new) & mask; env->svcr ^= change; + + if (change & R_SVCR_SM_MASK) { + arm_reset_sve_state(env); + } } static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index 94dc084135..f73bf4d285 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -29,22 +29,12 @@ #include "vec_internal.h" #include "sve_ldst_internal.h" -/* ResetSVEState */ -void arm_reset_sve_state(CPUARMState *env) -{ - memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs)); - /* Recall that FFR is stored as pregs[16]. */ - memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs)); - vfp_set_fpcr(env, 0x0800009f); -} - void helper_set_pstate_sm(CPUARMState *env, uint32_t i) { if (i == FIELD_EX64(env->svcr, SVCR, SM)) { return; } aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); - arm_reset_sve_state(env); arm_rebuild_hflags(env); } From fccb49182e23bd359092f7ab09bc7e60a0fff71a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:34 +0100 Subject: [PATCH 187/814] target/arm/sme: Reset ZA state in aarch64_set_svcr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-6-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/helper.c | 12 ++++++++++++ target/arm/sme_helper.c | 12 ------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 0ac867c411..564c5d9332 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6743,6 +6743,18 @@ void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) if (change & R_SVCR_SM_MASK) { arm_reset_sve_state(env); } + + /* + * ResetSMEState. + * + * SetPSTATE_ZA zeros on enable and disable. We can zero this only + * on enable: while disabled, the storage is inaccessible and the + * value does not matter. We're not saving the storage in vmstate + * when disabled either. + */ + if (change & new & R_SVCR_ZA_MASK) { + memset(env->zarray, 0, sizeof(env->zarray)); + } } static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index f73bf4d285..e146c17ba1 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -44,18 +44,6 @@ void helper_set_pstate_za(CPUARMState *env, uint32_t i) return; } aarch64_set_svcr(env, 0, R_SVCR_ZA_MASK); - - /* - * ResetSMEState. - * - * SetPSTATE_ZA zeros on enable and disable. We can zero this only - * on enable: while disabled, the storage is inaccessible and the - * value does not matter. We're not saving the storage in vmstate - * when disabled either. - */ - if (i) { - memset(env->zarray, 0, sizeof(env->zarray)); - } arm_rebuild_hflags(env); } From f4318557149184d6dac99e561acabcb602a84ee1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:35 +0100 Subject: [PATCH 188/814] target/arm/sme: Rebuild hflags in aarch64_set_svcr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-7-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- linux-user/aarch64/cpu_loop.c | 8 +------- linux-user/aarch64/signal.c | 3 --- target/arm/helper.c | 6 +++++- target/arm/sme_helper.c | 8 -------- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 5e93d27d8f..2e2f7cf218 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -89,14 +89,8 @@ void cpu_loop(CPUARMState *env) switch (trapnr) { case EXCP_SWI: - /* - * On syscall, PSTATE.ZA is preserved, along with the ZA matrix. - * PSTATE.SM is cleared, per SMSTOP, which does ResetSVEState. - */ + /* On syscall, PSTATE.ZA is preserved, PSTATE.SM is cleared. */ aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); - if (FIELD_EX64(env->svcr, SVCR, SM)) { - arm_rebuild_hflags(env); - } ret = do_syscall(env, env->xregs[8], env->xregs[0], diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index a326a6def5..b265cfd470 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -667,9 +667,6 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, /* Invoke the signal handler with both SM and ZA disabled. */ aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); - if (env->svcr) { - arm_rebuild_hflags(env); - } if (info) { tswap_siginfo(&frame->info, info); diff --git a/target/arm/helper.c b/target/arm/helper.c index 564c5d9332..8077967849 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6738,6 +6738,9 @@ void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) { uint64_t change = (env->svcr ^ new) & mask; + if (change == 0) { + return; + } env->svcr ^= change; if (change & R_SVCR_SM_MASK) { @@ -6755,6 +6758,8 @@ void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) if (change & new & R_SVCR_ZA_MASK) { memset(env->zarray, 0, sizeof(env->zarray)); } + + arm_rebuild_hflags(env); } static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -6763,7 +6768,6 @@ static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM)); helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA)); aarch64_set_svcr(env, value, -1); - arm_rebuild_hflags(env); } static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index e146c17ba1..3abe03e4cb 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -31,20 +31,12 @@ void helper_set_pstate_sm(CPUARMState *env, uint32_t i) { - if (i == FIELD_EX64(env->svcr, SVCR, SM)) { - return; - } aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); - arm_rebuild_hflags(env); } void helper_set_pstate_za(CPUARMState *env, uint32_t i) { - if (i == FIELD_EX64(env->svcr, SVCR, ZA)) { - return; - } aarch64_set_svcr(env, 0, R_SVCR_ZA_MASK); - arm_rebuild_hflags(env); } void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl) From 5c922ec5b136b452fe9d21e7581c99554ce650ed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Jan 2023 11:24:36 +0100 Subject: [PATCH 189/814] target/arm/sme: Unify set_pstate() SM/ZA helpers as set_svcr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the two helper_set_pstate_{sm,za} in this function. Do not call helper_* functions from svcr_write. Signed-off-by: Richard Henderson Reviewed-by: Fabiano Rosas Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230112102436.1913-8-philmd@linaro.org Message-Id: <20230112004322.161330-1-richard.henderson@linaro.org> [PMD: Split patch in multiple tiny steps] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/helper-sme.h | 3 +-- target/arm/helper.c | 2 -- target/arm/sme_helper.c | 9 ++------- target/arm/translate-a64.c | 10 ++-------- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/target/arm/helper-sme.h b/target/arm/helper-sme.h index d2d544a696..27eef49a11 100644 --- a/target/arm/helper-sme.h +++ b/target/arm/helper-sme.h @@ -17,8 +17,7 @@ * License along with this library; if not, see . */ -DEF_HELPER_FLAGS_2(set_pstate_sm, TCG_CALL_NO_RWG, void, env, i32) -DEF_HELPER_FLAGS_2(set_pstate_za, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_3(set_svcr, TCG_CALL_NO_RWG, void, env, i32, i32) DEF_HELPER_FLAGS_3(sme_zero, TCG_CALL_NO_RWG, void, env, i32, i32) diff --git a/target/arm/helper.c b/target/arm/helper.c index 8077967849..72b37b7cf1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6765,8 +6765,6 @@ void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM)); - helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA)); aarch64_set_svcr(env, value, -1); } diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index 3abe03e4cb..1e67fcac30 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -29,14 +29,9 @@ #include "vec_internal.h" #include "sve_ldst_internal.h" -void helper_set_pstate_sm(CPUARMState *env, uint32_t i) +void helper_set_svcr(CPUARMState *env, uint32_t val, uint32_t mask) { - aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); -} - -void helper_set_pstate_za(CPUARMState *env, uint32_t i) -{ - aarch64_set_svcr(env, 0, R_SVCR_ZA_MASK); + aarch64_set_svcr(env, val, mask); } void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 035e63bdc5..19cf371c4c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1847,14 +1847,8 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, if ((old ^ new) & msk) { /* At least one bit changes. */ - bool i = crm & 1; - - if ((crm & 2) && i != s->pstate_sm) { - gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i)); - } - if ((crm & 4) && i != s->pstate_za) { - gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i)); - } + gen_helper_set_svcr(cpu_env, tcg_constant_i32(new), + tcg_constant_i32(msk)); } else { s->base.is_jmp = DISAS_NEXT; } From 28fb921f02ef46676eb4b8a2eb9fb928f756b208 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Jan 2023 17:12:13 -1000 Subject: [PATCH 190/814] target/arm: Fix physical address resolution for MTE Conversion to probe_access_full missed applying the page offset. Fixes: b8967ddf ("target/arm: Use probe_access_full for MTE") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1416 Signed-off-by: Richard Henderson Message-id: 20230114031213.2970349-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 86b3754838..98bcf59c22 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -142,7 +142,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, * Remember these values across the second lookup below, * which may invalidate this pointer via tlb resize. */ - ptr_paddr = full->phys_addr; + ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK); attrs = full->attrs; full = NULL; From 4a1103afb16efa64600ef0c2b03afe60f689fdc9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Jan 2023 19:46:05 -1000 Subject: [PATCH 191/814] target/arm: Fix in_debug path in S1_ptw_translate During the conversion, the test against get_phys_addr_lpae got inverted, meaning that successful translations went to the 'failed' label. Cc: qemu-stable@nongnu.org Fixes: f3639a64f60 ("target/arm: Use softmmu tlbs for page table walking") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1417 Signed-off-by: Richard Henderson Message-id: 20230114054605.2977022-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell 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 4bda0590c7..57f3615a66 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -238,8 +238,8 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, }; GetPhysAddrResult s2 = { }; - if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, - false, &s2, fi)) { + if (get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, + false, &s2, fi)) { goto fail; } ptw->out_phys = s2.f.phys_addr; From 1e5da7e55332c76da2057e6d5298d7bf1733f104 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 16 Dec 2022 15:24:10 +0000 Subject: [PATCH 192/814] target/arm: Don't set EXC_RETURN.ES if Security Extension not present In v7m_exception_taken(), for v8M we set the EXC_RETURN.ES bit if either the exception targets Secure or if the CPU doesn't implement the Security Extension. This is incorrect: the v8M Arm ARM specifies that the ES bit should be RES0 if the Security Extension is not implemented, and the pseudocode agrees. Remove the incorrect condition, so that we leave the ES bit 0 if the Security Extension isn't implemented. This doesn't have any guest-visible effects for our current set of emulated CPUs, because all our v8M CPUs implement the Security Extension; but it's worth fixing in case we add a v8M CPU without the extension in future. Reported-by: Igor Kotrasinski Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/m_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index d87b9ecd12..e7e746ea18 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -879,7 +879,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, } lr &= ~R_V7M_EXCRET_ES_MASK; - if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) { + if (targets_secure) { lr |= R_V7M_EXCRET_ES_MASK; } lr &= ~R_V7M_EXCRET_SPSEL_MASK; From 5fc83f112866c4a136c36fd33e62c31228194bde Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Fri, 20 Jan 2023 16:59:28 +0100 Subject: [PATCH 193/814] target/arm: implement DBGCLAIM registers The architecture does not define any functionality for the CLAIM tag bits. So we will just keep the raw bits, as per spec. Signed-off-by: Evgeny Iakovlev Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230120155929.32384-2-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- target/arm/cpu.h | 1 + target/arm/debug_helper.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index f3ddc3b779..8cf70693be 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -495,6 +495,7 @@ typedef struct CPUArchState { uint64_t dbgbcr[16]; /* breakpoint control registers */ uint64_t dbgwvr[16]; /* watchpoint value registers */ uint64_t dbgwcr[16]; /* watchpoint control registers */ + uint64_t dbgclaim; /* DBGCLAIM bits */ uint64_t mdscr_el1; uint64_t oslsr_el1; /* OS Lock Status */ uint64_t osdlr_el1; /* OS DoubleLock status */ diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 2f6ddc0da5..f95a73329d 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -632,6 +632,24 @@ static void osdlr_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void dbgclaimset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.dbgclaim |= (value & 0xFF); +} + +static uint64_t dbgclaimset_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + /* CLAIM bits are RAO */ + return 0xFF; +} + +static void dbgclaimclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + env->cp15.dbgclaim &= ~(value & 0xFF); +} + static const ARMCPRegInfo debug_cp_reginfo[] = { /* * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped @@ -715,6 +733,21 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_tda, .type = ARM_CP_NOP }, + /* + * Dummy DBGCLAIM registers. + * "The architecture does not define any functionality for the CLAIM tag bits.", + * so we only keep the raw bits + */ + { .name = "DBGCLAIMSET_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6, + .type = ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tda, + .writefn = dbgclaimset_write, .readfn = dbgclaimset_read }, + { .name = "DBGCLAIMCLR_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 6, + .access = PL1_RW, .accessfn = access_tda, + .writefn = dbgclaimclr_write, .raw_writefn = raw_write, + .fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) }, }; static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { From b3aa2f21284d1d2713d0eb0253001eeebad3d582 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Fri, 20 Jan 2023 16:59:29 +0100 Subject: [PATCH 194/814] target/arm: provide stubs for more external debug registers Qemu doesn't implement Debug Communication Channel, as well as the rest of external debug interface. However, Microsoft Hyper-V in tries to access some of those registers during an EL2 context switch. Since there is no architectural way to not advertise support for external debug, provide RAZ/WI stubs for OSDTRRX_EL1, OSDTRTX_EL1 and OSECCR_EL1 registers in the same way the rest of DCM is currently done. Do account for access traps though with access_tda. Signed-off-by: Evgeny Iakovlev Reviewed-by: Peter Maydell Message-id: 20230120155929.32384-3-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- target/arm/debug_helper.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index f95a73329d..cced3f168d 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -682,6 +682,27 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, .access = PL0_R, .accessfn = access_tda, .type = ARM_CP_CONST, .resetvalue = 0 }, + /* + * OSDTRRX_EL1/OSDTRTX_EL1 are used for save and restore of DBGDTRRX_EL0. + * It is a component of the Debug Communications Channel, which is not implemented. + */ + { .name = "OSDTRRX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, + .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 2, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "OSDTRTX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, + .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = 0 }, + /* + * OSECCR_EL1 provides a mechanism for an operating system + * to access the contents of EDECCR. EDECCR is not implemented though, + * as is the rest of external device mechanism. + */ + { .name = "OSECCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, + .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_CONST, .resetvalue = 0 }, /* * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as * it is unlikely a guest will care. From 0371fa90a1b65b1536b3ff7ba583e4119c363eea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Jan 2023 11:44:50 -0800 Subject: [PATCH 195/814] target/arm: Reorg do_coproc_insn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the ri == NULL case to the top of the function and return. This allows the else to be removed and the code unindented. Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Message-id: 20230106194451.1213153-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/translate.c | 406 ++++++++++++++++++++--------------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 1dcaefb8e7..40f9f07ea3 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4715,220 +4715,220 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, bool isread, int rt, int rt2) { const ARMCPRegInfo *ri; + bool need_exit_tb; ri = get_arm_cp_reginfo(s->cp_regs, ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2)); - if (ri) { - bool need_exit_tb; - /* Check access permissions */ - if (!cp_access_ok(s->current_el, ri, isread)) { - unallocated_encoding(s); - return; - } - - if (s->hstr_active || ri->accessfn || - (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) { - /* Emit code to perform further access permissions checks at - * runtime; this may result in an exception. - * Note that on XScale all cp0..c13 registers do an access check - * call in order to handle c15_cpar. - */ - uint32_t syndrome; - - /* Note that since we are an implementation which takes an - * exception on a trapped conditional instruction only if the - * instruction passes its condition code check, we can take - * advantage of the clause in the ARM ARM that allows us to set - * the COND field in the instruction to 0xE in all cases. - * We could fish the actual condition out of the insn (ARM) - * or the condexec bits (Thumb) but it isn't necessary. - */ - switch (cpnum) { - case 14: - if (is64) { - syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, false); - } else { - syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, false); - } - break; - case 15: - if (is64) { - syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, false); - } else { - syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, false); - } - break; - default: - /* ARMv8 defines that only coprocessors 14 and 15 exist, - * so this can only happen if this is an ARMv7 or earlier CPU, - * in which case the syndrome information won't actually be - * guest visible. - */ - assert(!arm_dc_feature(s, ARM_FEATURE_V8)); - syndrome = syn_uncategorized(); - break; - } - - gen_set_condexec(s); - gen_update_pc(s, 0); - gen_helper_access_check_cp_reg(cpu_env, - tcg_constant_ptr(ri), - tcg_constant_i32(syndrome), - tcg_constant_i32(isread)); - } else if (ri->type & ARM_CP_RAISES_EXC) { - /* - * The readfn or writefn might raise an exception; - * synchronize the CPU state in case it does. - */ - gen_set_condexec(s); - gen_update_pc(s, 0); - } - - /* Handle special cases first */ - switch (ri->type & ARM_CP_SPECIAL_MASK) { - case 0: - break; - case ARM_CP_NOP: - return; - case ARM_CP_WFI: - if (isread) { - unallocated_encoding(s); - return; - } - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_WFI; - return; - default: - g_assert_not_reached(); - } - - if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { - gen_io_start(); - } - - if (isread) { - /* Read */ - if (is64) { - TCGv_i64 tmp64; - TCGv_i32 tmp; - if (ri->type & ARM_CP_CONST) { - tmp64 = tcg_constant_i64(ri->resetvalue); - } else if (ri->readfn) { - tmp64 = tcg_temp_new_i64(); - gen_helper_get_cp_reg64(tmp64, cpu_env, - tcg_constant_ptr(ri)); - } else { - tmp64 = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); - } - tmp = tcg_temp_new_i32(); - tcg_gen_extrl_i64_i32(tmp, tmp64); - store_reg(s, rt, tmp); - tmp = tcg_temp_new_i32(); - tcg_gen_extrh_i64_i32(tmp, tmp64); - tcg_temp_free_i64(tmp64); - store_reg(s, rt2, tmp); - } else { - TCGv_i32 tmp; - if (ri->type & ARM_CP_CONST) { - tmp = tcg_constant_i32(ri->resetvalue); - } else if (ri->readfn) { - tmp = tcg_temp_new_i32(); - gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri)); - } else { - tmp = load_cpu_offset(ri->fieldoffset); - } - if (rt == 15) { - /* Destination register of r15 for 32 bit loads sets - * the condition codes from the high 4 bits of the value - */ - gen_set_nzcv(tmp); - tcg_temp_free_i32(tmp); - } else { - store_reg(s, rt, tmp); - } - } + if (!ri) { + /* + * Unknown register; this might be a guest error or a QEMU + * unimplemented feature. + */ + if (is64) { + qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " + "64 bit system register cp:%d opc1: %d crm:%d " + "(%s)\n", + isread ? "read" : "write", cpnum, opc1, crm, + s->ns ? "non-secure" : "secure"); } else { - /* Write */ - if (ri->type & ARM_CP_CONST) { - /* If not forbidden by access permissions, treat as WI */ - return; - } - - if (is64) { - TCGv_i32 tmplo, tmphi; - TCGv_i64 tmp64 = tcg_temp_new_i64(); - tmplo = load_reg(s, rt); - tmphi = load_reg(s, rt2); - tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi); - tcg_temp_free_i32(tmplo); - tcg_temp_free_i32(tmphi); - if (ri->writefn) { - gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), - tmp64); - } else { - tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); - } - tcg_temp_free_i64(tmp64); - } else { - TCGv_i32 tmp = load_reg(s, rt); - if (ri->writefn) { - gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp); - tcg_temp_free_i32(tmp); - } else { - store_cpu_offset(tmp, ri->fieldoffset, 4); - } - } + qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " + "system register cp:%d opc1:%d crn:%d crm:%d " + "opc2:%d (%s)\n", + isread ? "read" : "write", cpnum, opc1, crn, + crm, opc2, s->ns ? "non-secure" : "secure"); } - - /* I/O operations must end the TB here (whether read or write) */ - need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && - (ri->type & ARM_CP_IO)); - - if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { - /* - * A write to any coprocessor register that ends a TB - * must rebuild the hflags for the next TB. - */ - gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL); - /* - * We default to ending the TB on a coprocessor register write, - * but allow this to be suppressed by the register definition - * (usually only necessary to work around guest bugs). - */ - need_exit_tb = true; - } - if (need_exit_tb) { - gen_lookup_tb(s); - } - + unallocated_encoding(s); return; } - /* Unknown register; this might be a guest error or a QEMU - * unimplemented feature. - */ - if (is64) { - qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " - "64 bit system register cp:%d opc1: %d crm:%d " - "(%s)\n", - isread ? "read" : "write", cpnum, opc1, crm, - s->ns ? "non-secure" : "secure"); - } else { - qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 " - "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d " - "(%s)\n", - isread ? "read" : "write", cpnum, opc1, crn, crm, opc2, - s->ns ? "non-secure" : "secure"); + /* Check access permissions */ + if (!cp_access_ok(s->current_el, ri, isread)) { + unallocated_encoding(s); + return; } - unallocated_encoding(s); - return; + if (s->hstr_active || ri->accessfn || + (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) { + /* + * Emit code to perform further access permissions checks at + * runtime; this may result in an exception. + * Note that on XScale all cp0..c13 registers do an access check + * call in order to handle c15_cpar. + */ + uint32_t syndrome; + + /* + * Note that since we are an implementation which takes an + * exception on a trapped conditional instruction only if the + * instruction passes its condition code check, we can take + * advantage of the clause in the ARM ARM that allows us to set + * the COND field in the instruction to 0xE in all cases. + * We could fish the actual condition out of the insn (ARM) + * or the condexec bits (Thumb) but it isn't necessary. + */ + switch (cpnum) { + case 14: + if (is64) { + syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2, + isread, false); + } else { + syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm, + rt, isread, false); + } + break; + case 15: + if (is64) { + syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2, + isread, false); + } else { + syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm, + rt, isread, false); + } + break; + default: + /* + * ARMv8 defines that only coprocessors 14 and 15 exist, + * so this can only happen if this is an ARMv7 or earlier CPU, + * in which case the syndrome information won't actually be + * guest visible. + */ + assert(!arm_dc_feature(s, ARM_FEATURE_V8)); + syndrome = syn_uncategorized(); + break; + } + + gen_set_condexec(s); + gen_update_pc(s, 0); + gen_helper_access_check_cp_reg(cpu_env, + tcg_constant_ptr(ri), + tcg_constant_i32(syndrome), + tcg_constant_i32(isread)); + } else if (ri->type & ARM_CP_RAISES_EXC) { + /* + * The readfn or writefn might raise an exception; + * synchronize the CPU state in case it does. + */ + gen_set_condexec(s); + gen_update_pc(s, 0); + } + + /* Handle special cases first */ + switch (ri->type & ARM_CP_SPECIAL_MASK) { + case 0: + break; + case ARM_CP_NOP: + return; + case ARM_CP_WFI: + if (isread) { + unallocated_encoding(s); + return; + } + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_WFI; + return; + default: + g_assert_not_reached(); + } + + if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { + gen_io_start(); + } + + if (isread) { + /* Read */ + if (is64) { + TCGv_i64 tmp64; + TCGv_i32 tmp; + if (ri->type & ARM_CP_CONST) { + tmp64 = tcg_constant_i64(ri->resetvalue); + } else if (ri->readfn) { + tmp64 = tcg_temp_new_i64(); + gen_helper_get_cp_reg64(tmp64, cpu_env, + tcg_constant_ptr(ri)); + } else { + tmp64 = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); + } + tmp = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmp, tmp64); + store_reg(s, rt, tmp); + tmp = tcg_temp_new_i32(); + tcg_gen_extrh_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); + store_reg(s, rt2, tmp); + } else { + TCGv_i32 tmp; + if (ri->type & ARM_CP_CONST) { + tmp = tcg_constant_i32(ri->resetvalue); + } else if (ri->readfn) { + tmp = tcg_temp_new_i32(); + gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri)); + } else { + tmp = load_cpu_offset(ri->fieldoffset); + } + if (rt == 15) { + /* Destination register of r15 for 32 bit loads sets + * the condition codes from the high 4 bits of the value + */ + gen_set_nzcv(tmp); + tcg_temp_free_i32(tmp); + } else { + store_reg(s, rt, tmp); + } + } + } else { + /* Write */ + if (ri->type & ARM_CP_CONST) { + /* If not forbidden by access permissions, treat as WI */ + return; + } + + if (is64) { + TCGv_i32 tmplo, tmphi; + TCGv_i64 tmp64 = tcg_temp_new_i64(); + tmplo = load_reg(s, rt); + tmphi = load_reg(s, rt2); + tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi); + tcg_temp_free_i32(tmplo); + tcg_temp_free_i32(tmphi); + if (ri->writefn) { + gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tmp64); + } else { + tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); + } + tcg_temp_free_i64(tmp64); + } else { + TCGv_i32 tmp = load_reg(s, rt); + if (ri->writefn) { + gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp); + tcg_temp_free_i32(tmp); + } else { + store_cpu_offset(tmp, ri->fieldoffset, 4); + } + } + } + + /* I/O operations must end the TB here (whether read or write) */ + need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && + (ri->type & ARM_CP_IO)); + + if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { + /* + * A write to any coprocessor register that ends a TB + * must rebuild the hflags for the next TB. + */ + gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL); + /* + * We default to ending the TB on a coprocessor register write, + * but allow this to be suppressed by the register definition + * (usually only necessary to work around guest bugs). + */ + need_exit_tb = true; + } + if (need_exit_tb) { + gen_lookup_tb(s); + } } /* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */ From 3b07a936d3bfe97b07ddffcfbb532985a88033dd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Jan 2023 11:44:51 -0800 Subject: [PATCH 196/814] target/arm: Look up ARMCPRegInfo at runtime Do not encode the pointer as a constant in the opcode stream. This pointer is specific to the cpu that first generated the translation, which runs into problems with both hot-pluggable cpus and user-only threads, as cpus are removed. It's also a potential correctness issue in the theoretical case of a slightly-heterogenous system, because if CPU 0 generates a TB and then CPU 1 executes it, CPU 1 will end up using CPU 0's hash table, which might have a wrong set of registers in it. (All our current systems are either completely homogenous, M-profile, or have CPUs sufficiently different that they wouldn't be sharing TBs anyway because the differences would show up in the TB flags, so the correctness issue is only theoretical, not practical.) Perform the lookup in either helper_access_check_cp_reg, or a new helper_lookup_cp_reg. Signed-off-by: Richard Henderson Message-id: 20230106194451.1213153-3-richard.henderson@linaro.org [PMM: added note in commit message about correctness issue] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.h | 11 +++++---- target/arm/op_helper.c | 27 ++++++++++++++------ target/arm/translate-a64.c | 49 ++++++++++++++++++++++--------------- target/arm/translate.c | 50 +++++++++++++++++++++++++------------- target/arm/translate.h | 7 ++++++ 5 files changed, 95 insertions(+), 49 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 92f36d9dbb..018b00ea75 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -79,11 +79,12 @@ 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, void, env, ptr, i32, i32) -DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) -DEF_HELPER_2(get_cp_reg, i32, env, ptr) -DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) -DEF_HELPER_2(get_cp_reg64, i64, env, ptr) +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_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) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 70672bcd9f..31f89db899 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -624,14 +624,16 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno) } } -void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, - uint32_t isread) +const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, + uint32_t syndrome, uint32_t isread) { ARMCPU *cpu = env_archcpu(env); - const ARMCPRegInfo *ri = rip; + const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key); CPAccessResult res = CP_ACCESS_OK; int target_el; + assert(ri != NULL); + if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { res = CP_ACCESS_TRAP; @@ -663,7 +665,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, res = ri->accessfn(env, ri, isread); } if (likely(res == CP_ACCESS_OK)) { - return; + return ri; } fail: @@ -705,7 +707,16 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, raise_exception(env, EXCP_UDEF, syndrome, target_el); } -void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value) +const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key) +{ + ARMCPU *cpu = env_archcpu(env); + const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key); + + assert(ri != NULL); + return ri; +} + +void HELPER(set_cp_reg)(CPUARMState *env, const void *rip, uint32_t value) { const ARMCPRegInfo *ri = rip; @@ -718,7 +729,7 @@ void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value) } } -uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip) +uint32_t HELPER(get_cp_reg)(CPUARMState *env, const void *rip) { const ARMCPRegInfo *ri = rip; uint32_t res; @@ -734,7 +745,7 @@ uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip) return res; } -void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value) +void HELPER(set_cp_reg64)(CPUARMState *env, const void *rip, uint64_t value) { const ARMCPRegInfo *ri = rip; @@ -747,7 +758,7 @@ void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value) } } -uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) +uint64_t HELPER(get_cp_reg64)(CPUARMState *env, const void *rip) { const ARMCPRegInfo *ri = rip; uint64_t res; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 19cf371c4c..52b1b8a1f0 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1939,13 +1939,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, unsigned int op0, unsigned int op1, unsigned int op2, unsigned int crn, unsigned int crm, unsigned int rt) { - const ARMCPRegInfo *ri; + uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, + crn, crm, op0, op1, op2); + const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); + TCGv_ptr tcg_ri = NULL; TCGv_i64 tcg_rt; - ri = get_arm_cp_reginfo(s->cp_regs, - ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, - crn, crm, op0, op1, op2)); - if (!ri) { /* Unknown register; this might be a guest error or a QEMU * unimplemented feature. @@ -1971,8 +1970,9 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); gen_a64_update_pc(s, 0); - gen_helper_access_check_cp_reg(cpu_env, - tcg_constant_ptr(ri), + tcg_ri = tcg_temp_new_ptr(); + gen_helper_access_check_cp_reg(tcg_ri, cpu_env, + tcg_constant_i32(key), tcg_constant_i32(syndrome), tcg_constant_i32(isread)); } else if (ri->type & ARM_CP_RAISES_EXC) { @@ -1988,7 +1988,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, case 0: break; case ARM_CP_NOP: - return; + goto exit; case ARM_CP_NZCV: tcg_rt = cpu_reg(s, rt); if (isread) { @@ -1996,14 +1996,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } else { gen_set_nzcv(tcg_rt); } - return; + goto exit; case ARM_CP_CURRENTEL: /* Reads as current EL value from pstate, which is * guaranteed to be constant by the tb flags. */ tcg_rt = cpu_reg(s, rt); tcg_gen_movi_i64(tcg_rt, s->current_el << 2); - return; + goto exit; case ARM_CP_DC_ZVA: /* Writes clear the aligned block of memory which rt points into. */ if (s->mte_active[0]) { @@ -2020,7 +2020,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); } gen_helper_dc_zva(cpu_env, tcg_rt); - return; + goto exit; case ARM_CP_DC_GVA: { TCGv_i64 clean_addr, tag; @@ -2041,7 +2041,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, tcg_temp_free_i64(tag); } } - return; + goto exit; case ARM_CP_DC_GZVA: { TCGv_i64 clean_addr, tag; @@ -2059,16 +2059,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, tcg_temp_free_i64(tag); } } - return; + goto exit; default: g_assert_not_reached(); } if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) { - return; + goto exit; } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) { - return; + goto exit; } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) { - return; + goto exit; } if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { @@ -2081,16 +2081,22 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, if (ri->type & ARM_CP_CONST) { tcg_gen_movi_i64(tcg_rt, ri->resetvalue); } else if (ri->readfn) { - gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_constant_ptr(ri)); + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } + gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_ri); } else { tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset); } } else { if (ri->type & ARM_CP_CONST) { /* If not forbidden by access permissions, treat as WI */ - return; + goto exit; } else if (ri->writefn) { - gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tcg_rt); + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } + gen_helper_set_cp_reg64(cpu_env, tcg_ri, tcg_rt); } else { tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset); } @@ -2113,6 +2119,11 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, */ s->base.is_jmp = DISAS_UPDATE_EXIT; } + + exit: + if (tcg_ri) { + tcg_temp_free_ptr(tcg_ri); + } } /* System diff --git a/target/arm/translate.c b/target/arm/translate.c index 40f9f07ea3..365e02fb0b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4714,12 +4714,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, int opc1, int crn, int crm, int opc2, bool isread, int rt, int rt2) { - const ARMCPRegInfo *ri; + uint32_t key = ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2); + const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); + TCGv_ptr tcg_ri = NULL; bool need_exit_tb; - ri = get_arm_cp_reginfo(s->cp_regs, - ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2)); - if (!ri) { /* * Unknown register; this might be a guest error or a QEMU @@ -4800,8 +4799,9 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, gen_set_condexec(s); gen_update_pc(s, 0); - gen_helper_access_check_cp_reg(cpu_env, - tcg_constant_ptr(ri), + tcg_ri = tcg_temp_new_ptr(); + gen_helper_access_check_cp_reg(tcg_ri, cpu_env, + tcg_constant_i32(key), tcg_constant_i32(syndrome), tcg_constant_i32(isread)); } else if (ri->type & ARM_CP_RAISES_EXC) { @@ -4818,15 +4818,15 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, case 0: break; case ARM_CP_NOP: - return; + goto exit; case ARM_CP_WFI: if (isread) { unallocated_encoding(s); - return; + } else { + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_WFI; } - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_WFI; - return; + goto exit; default: g_assert_not_reached(); } @@ -4843,9 +4843,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, if (ri->type & ARM_CP_CONST) { tmp64 = tcg_constant_i64(ri->resetvalue); } else if (ri->readfn) { + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } tmp64 = tcg_temp_new_i64(); - gen_helper_get_cp_reg64(tmp64, cpu_env, - tcg_constant_ptr(ri)); + gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri); } else { tmp64 = tcg_temp_new_i64(); tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset); @@ -4862,8 +4864,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, if (ri->type & ARM_CP_CONST) { tmp = tcg_constant_i32(ri->resetvalue); } else if (ri->readfn) { + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } tmp = tcg_temp_new_i32(); - gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri)); + gen_helper_get_cp_reg(tmp, cpu_env, tcg_ri); } else { tmp = load_cpu_offset(ri->fieldoffset); } @@ -4881,7 +4886,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, /* Write */ if (ri->type & ARM_CP_CONST) { /* If not forbidden by access permissions, treat as WI */ - return; + goto exit; } if (is64) { @@ -4893,7 +4898,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, tcg_temp_free_i32(tmplo); tcg_temp_free_i32(tmphi); if (ri->writefn) { - gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tmp64); + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } + gen_helper_set_cp_reg64(cpu_env, tcg_ri, tmp64); } else { tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); } @@ -4901,7 +4909,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, } else { TCGv_i32 tmp = load_reg(s, rt); if (ri->writefn) { - gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp); + if (!tcg_ri) { + tcg_ri = gen_lookup_cp_reg(key); + } + gen_helper_set_cp_reg(cpu_env, tcg_ri, tmp); tcg_temp_free_i32(tmp); } else { store_cpu_offset(tmp, ri->fieldoffset, 4); @@ -4929,6 +4940,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, if (need_exit_tb) { gen_lookup_tb(s); } + + exit: + if (tcg_ri) { + tcg_temp_free_ptr(tcg_ri); + } } /* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */ diff --git a/target/arm/translate.h b/target/arm/translate.h index 3cdc7dbc2f..f17f095cbe 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -610,6 +610,13 @@ static inline void set_disas_label(DisasContext *s, DisasLabel l) s->pc_save = l.pc_save; } +static inline TCGv_ptr gen_lookup_cp_reg(uint32_t key) +{ + TCGv_ptr ret = tcg_temp_new_ptr(); + gen_helper_lookup_cp_reg(ret, cpu_env, tcg_constant_i32(key)); + return ret; +} + /* * Helpers for implementing sets of trans_* functions. * Defer the implementation of NAME to FUNC, with optional extra arguments. From 816a430c517eae48da5a31207ca43151df3203b0 Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Sun, 10 Jul 2022 20:08:49 +0800 Subject: [PATCH 197/814] util/aio: Defer disabling poll mode as long as possible When we measure FIO read performance (cache=writethrough, bs=4k, iodepth=64) in VMs, ~80K/s notifications (e.g., EPT_MISCONFIG) are observed from guest to qemu. It turns out those frequent notificatons are caused by interference from worker threads. Worker threads queue bottom halves after completing IO requests. Pending bottom halves may lead to either aio_compute_timeout() zeros timeout and pass it to try_poll_mode() or run_poll_handlers() returns no progress after noticing pending aio_notify() events. Both cause run_poll_handlers() to call poll_set_started(false) to disable poll mode. However, for both cases, as timeout is already zeroed, the event loop (i.e., aio_poll()) just processes bottom halves and then starts the next event loop iteration. So, disabling poll mode has no value but leads to unnecessary notifications from guest. To minimize unnecessary notifications from guest, defer disabling poll mode to when the event loop is about to be blocked. With this patch applied, FIO seq-read performance (bs=4k, iodepth=64, cache=writethrough) in VMs increases from 330K/s to 413K/s IOPS. Suggested-by: Stefan Hajnoczi Signed-off-by: Chao Gao Message-id: 20220710120849.63086-1-chao.gao@intel.com Signed-off-by: Stefan Hajnoczi --- util/aio-posix.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/util/aio-posix.c b/util/aio-posix.c index 731f3826c0..6cc6256d53 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -585,18 +585,16 @@ static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns); if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) { + /* + * Enable poll mode. It pairs with the poll_set_started() in + * aio_poll() which disables poll mode. + */ poll_set_started(ctx, ready_list, true); if (run_poll_handlers(ctx, ready_list, max_ns, timeout)) { return true; } } - - if (poll_set_started(ctx, ready_list, false)) { - *timeout = 0; - return true; - } - return false; } @@ -657,6 +655,17 @@ bool aio_poll(AioContext *ctx, bool blocking) * system call---a single round of run_poll_handlers_once suffices. */ if (timeout || ctx->fdmon_ops->need_wait(ctx)) { + /* + * Disable poll mode. poll mode should be disabled before the call + * of ctx->fdmon_ops->wait() so that guest's notification can wake + * up IO threads when some work becomes pending. It is essential to + * avoid hangs or unnecessary latency. + */ + if (poll_set_started(ctx, &ready_list, false)) { + timeout = 0; + progress = true; + } + ctx->fdmon_ops->wait(ctx, &ready_list, timeout); } From a937f8e8577babc32b24d4f518cb336c013cd14f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 2 Nov 2022 14:23:37 -0400 Subject: [PATCH 198/814] virtio-blk: simplify virtio_blk_dma_restart_cb() virtio_blk_dma_restart_cb() is tricky because the BH must deal with virtio_blk_data_plane_start()/virtio_blk_data_plane_stop() being called. There are two issues with the code: 1. virtio_blk_realize() should use qdev_add_vm_change_state_handler() instead of qemu_add_vm_change_state_handler(). This ensures the ordering with virtio_init()'s vm change state handler that calls virtio_blk_data_plane_start()/virtio_blk_data_plane_stop() is well-defined. Then blk's AioContext is guaranteed to be up-to-date in virtio_blk_dma_restart_cb() and it's no longer necessary to have a special case for virtio_blk_data_plane_start(). 2. Only blk_drain() waits for virtio_blk_dma_restart_cb()'s blk_inc_in_flight() to be decremented. The bdrv_drain() family of functions do not wait for BlockBackend's in_flight counter to reach zero. virtio_blk_data_plane_stop() relies on blk_set_aio_context()'s implicit drain, but that's a bdrv_drain() and not a blk_drain(). Note that virtio_blk_reset() already correctly relies on blk_drain(). If virtio_blk_data_plane_stop() switches to blk_drain() then we can properly wait for pending virtio_blk_dma_restart_bh() calls. Once these issues are taken care of the code becomes simpler. This change is in preparation for multiple IOThreads in virtio-blk where we need to clean up the multi-threading behavior. I ran the reproducer from commit 49b44549ace7 ("virtio-blk: On restart, process queued requests in the proper context") to check that there is no regression. Cc: Sergio Lopez Cc: Kevin Wolf Cc: Emanuele Giuseppe Esposito Signed-off-by: Stefan Hajnoczi Acked-by: Michael S. Tsirkin Reviewed-by: Emanuele Giuseppe Esposito Message-id: 20221102182337.252202-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/dataplane/virtio-blk.c | 17 +++++------- hw/block/virtio-blk.c | 46 ++++++++++++++------------------- include/hw/virtio/virtio-blk.h | 2 -- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 26f965cabc..b28d81737e 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -237,9 +237,6 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) goto fail_aio_context; } - /* Process queued requests before the ones in vring */ - virtio_blk_process_queued_requests(vblk, false); - /* Kick right away to begin processing requests already in vring */ for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); @@ -272,11 +269,6 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) fail_host_notifiers: k->set_guest_notifiers(qbus->parent, nvqs, false); fail_guest_notifiers: - /* - * If we failed to set up the guest notifiers queued requests will be - * processed on the main context. - */ - virtio_blk_process_queued_requests(vblk, false); vblk->dataplane_disabled = true; s->starting = false; vblk->dataplane_started = true; @@ -325,8 +317,13 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) aio_context_acquire(s->ctx); aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s); - /* Drain and try to switch bs back to the QEMU main loop. If other users - * keep the BlockBackend in the iothread, that's ok */ + /* Wait for virtio_blk_dma_restart_bh() and in flight I/O to complete */ + blk_drain(s->conf->conf.blk); + + /* + * Try to switch bs back to the QEMU main loop. If other users keep the + * BlockBackend in the iothread, that's ok + */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context(), NULL); aio_context_release(s->ctx); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f717550fdc..1762517878 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -806,8 +806,10 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) virtio_blk_handle_vq(s, vq); } -void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) +static void virtio_blk_dma_restart_bh(void *opaque) { + VirtIOBlock *s = opaque; + VirtIOBlockReq *req = s->rq; MultiReqBuffer mrb = {}; @@ -834,43 +836,27 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) if (mrb.num_reqs) { virtio_blk_submit_multireq(s, &mrb); } - if (is_bh) { - blk_dec_in_flight(s->conf.conf.blk); - } + + /* Paired with inc in virtio_blk_dma_restart_cb() */ + blk_dec_in_flight(s->conf.conf.blk); + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } -static void virtio_blk_dma_restart_bh(void *opaque) -{ - VirtIOBlock *s = opaque; - - qemu_bh_delete(s->bh); - s->bh = NULL; - - virtio_blk_process_queued_requests(s, true); -} - static void virtio_blk_dma_restart_cb(void *opaque, bool running, RunState state) { VirtIOBlock *s = opaque; - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); - VirtioBusState *bus = VIRTIO_BUS(qbus); if (!running) { return; } - /* - * If ioeventfd is enabled, don't schedule the BH here as queued - * requests will be processed while starting the data plane. - */ - if (!s->bh && !virtio_bus_ioeventfd_enabled(bus)) { - s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), - virtio_blk_dma_restart_bh, s); - blk_inc_in_flight(s->conf.conf.blk); - qemu_bh_schedule(s->bh); - } + /* Paired with dec in virtio_blk_dma_restart_bh() */ + blk_inc_in_flight(s->conf.conf.blk); + + aio_bh_schedule_oneshot(blk_get_aio_context(s->conf.conf.blk), + virtio_blk_dma_restart_bh, s); } static void virtio_blk_reset(VirtIODevice *vdev) @@ -1213,7 +1199,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); + /* + * This must be after virtio_init() so virtio_blk_dma_restart_cb() gets + * 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); + blk_ram_registrar_init(&s->blk_ram_registrar, s->blk); blk_set_dev_ops(s->blk, &virtio_block_ops, s); diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 7f589b4146..dafec432ce 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -55,7 +55,6 @@ struct VirtIOBlock { VirtIODevice parent_obj; BlockBackend *blk; void *rq; - QEMUBH *bh; VirtIOBlkConf conf; unsigned short sector_mask; bool original_wce; @@ -93,6 +92,5 @@ typedef struct MultiReqBuffer { } MultiReqBuffer; void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); -void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); #endif From 4f01a9bb0461e8c11ee0c94d90a504cb7d580a85 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Mon, 23 Jan 2023 13:39:27 +0100 Subject: [PATCH 199/814] block/blkio: Fix inclusion of required headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After recent header file inclusion rework the build fails when the blkio module is enabled: ../block/blkio.c: In function ‘blkio_detach_aio_context’: ../block/blkio.c:321:24: error: implicit declaration of function ‘bdrv_get_aio_context’; did you mean ‘qemu_get_aio_context’? [-Werror=implicit-function-declaration] 321 | aio_set_fd_handler(bdrv_get_aio_context(bs), | ^~~~~~~~~~~~~~~~~~~~ | qemu_get_aio_context ../block/blkio.c:321:24: error: nested extern declaration of ‘bdrv_get_aio_context’ [-Werror=nested-externs] ../block/blkio.c:321:24: error: passing argument 1 of ‘aio_set_fd_handler’ makes pointer from integer without a cast [-Werror=int-conversion] 321 | aio_set_fd_handler(bdrv_get_aio_context(bs), | ^~~~~~~~~~~~~~~~~~~~~~~~ | | | int In file included from /home/pipo/git/qemu.git/include/qemu/job.h:33, from /home/pipo/git/qemu.git/include/block/blockjob.h:30, from /home/pipo/git/qemu.git/include/block/block_int-global-state.h:28, from /home/pipo/git/qemu.git/include/block/block_int.h:27, from ../block/blkio.c:13: /home/pipo/git/qemu.git/include/block/aio.h:476:37: note: expected ‘AioContext *’ but argument is of type ‘int’ 476 | void aio_set_fd_handler(AioContext *ctx, | ~~~~~~~~~~~~^~~ ../block/blkio.c: In function ‘blkio_file_open’: ../block/blkio.c:821:34: error: passing argument 2 of ‘blkio_attach_aio_context’ makes pointer from integer without a cast [-Werror=int-conversion] 821 | blkio_attach_aio_context(bs, bdrv_get_aio_context(bs)); | ^~~~~~~~~~~~~~~~~~~~~~~~ | | | int Fix it by including 'block/block-io.h' which contains the required declarations. Fixes: e2c1c34f139f49ef909bb4322607fb8b39002312 Signed-off-by: Peter Krempa Reviewed-by: Markus Armbruster Message-id: 2bc956011404a1ab03342aefde0087b5b4762562.1674477350.git.pkrempa@redhat.com Signed-off-by: Stefan Hajnoczi --- block/blkio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/blkio.c b/block/blkio.c index 5eae3adfaf..6ad86b23d1 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -19,6 +19,8 @@ #include "qemu/module.h" #include "exec/memory.h" /* for ram_block_discard_disable() */ +#include "block/block-io.h" + /* * Keep the QEMU BlockDriver names identical to the libblkio driver names. * Using macros instead of typing out the string literals avoids typos. From 9fd86b518ee0abc0f0c013ce51e5384b8109d94c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Jan 2023 16:03:44 -1000 Subject: [PATCH 200/814] tcg: Avoid recursion in tcg_gen_mulu2_i32 We have a test for one of TCG_TARGET_HAS_mulu2_i32 or TCG_TARGET_HAS_muluh_i32 being defined, but the test became non-functional when we changed to always define all of these macros. Replace this with a build-time test in tcg_gen_mulu2_i32. Fixes: 25c4d9cc845 ("tcg: Always define all of the TCGOpcode enum members.") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1435 Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 7 ------- tcg/tcg-op.c | 4 +++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 6f497172f8..9a0ae7d20b 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -155,13 +155,6 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_rem_i64 0 #endif -/* For 32-bit targets, some sort of unsigned widening multiply is required. */ -#if TCG_TARGET_REG_BITS == 32 \ - && !(defined(TCG_TARGET_HAS_mulu2_i32) \ - || defined(TCG_TARGET_HAS_muluh_i32)) -# error "Missing unsigned widening multiply" -#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 9fa9f1b0fd..326a9180ef 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -874,7 +874,7 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); tcg_gen_mov_i32(rl, t); tcg_temp_free_i32(t); - } else { + } else if (TCG_TARGET_REG_BITS == 64) { TCGv_i64 t0 = tcg_temp_new_i64(); TCGv_i64 t1 = tcg_temp_new_i64(); tcg_gen_extu_i32_i64(t0, arg1); @@ -883,6 +883,8 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_extr_i64_i32(rl, rh, t0); tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); + } else { + qemu_build_not_reached(); } } From 1b18d1fa05bbf8d28778b0eb65dc21d4cd7c6950 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Oct 2022 11:24:52 +1100 Subject: [PATCH 201/814] tcg/arm: Use register pair allocation for qemu_{ld,st}_i64 Although we still can't use ldrd and strd for all operations, increase the chances by getting the register allocation correct. Signed-off-by: Richard Henderson --- tcg/arm/tcg-target-con-set.h | 7 ++++--- tcg/arm/tcg-target-con-str.h | 2 ++ tcg/arm/tcg-target.c.inc | 28 ++++++++++++++++++---------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/tcg/arm/tcg-target-con-set.h b/tcg/arm/tcg-target-con-set.h index 3685e1786a..b8849b2478 100644 --- a/tcg/arm/tcg-target-con-set.h +++ b/tcg/arm/tcg-target-con-set.h @@ -15,8 +15,9 @@ C_O0_I2(r, rIN) C_O0_I2(s, s) C_O0_I2(w, r) C_O0_I3(s, s, s) +C_O0_I3(S, p, s) C_O0_I4(r, r, rI, rI) -C_O0_I4(s, s, s, s) +C_O0_I4(S, p, s, s) C_O1_I1(r, l) C_O1_I1(r, r) C_O1_I1(w, r) @@ -38,8 +39,8 @@ C_O1_I2(w, w, wZ) C_O1_I3(w, w, w, w) C_O1_I4(r, r, r, rI, rI) C_O1_I4(r, r, rIN, rIK, 0) -C_O2_I1(r, r, l) -C_O2_I2(r, r, l, l) +C_O2_I1(e, p, l) +C_O2_I2(e, p, l, l) 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-con-str.h b/tcg/arm/tcg-target-con-str.h index 8f501149e1..24b4b59feb 100644 --- a/tcg/arm/tcg-target-con-str.h +++ b/tcg/arm/tcg-target-con-str.h @@ -8,9 +8,11 @@ * Define constraint letters for register sets: * REGS(letter, register_mask) */ +REGS('e', ALL_GENERAL_REGS & 0x5555) /* even regs */ REGS('r', ALL_GENERAL_REGS) REGS('l', ALL_QLOAD_REGS) REGS('s', ALL_QSTORE_REGS) +REGS('S', ALL_QSTORE_REGS & 0x5555) /* even qstore */ REGS('w', ALL_VECTOR_REGS) /* diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 6abe94137e..0f5f9f4925 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1694,9 +1694,11 @@ static void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc, tcg_out_ld32_r(s, COND_AL, datalo, addrlo, addend); break; case MO_UQ: + /* We used pair allocation for datalo, so already should be aligned. */ + tcg_debug_assert((datalo & 1) == 0); + tcg_debug_assert(datahi == datalo + 1); /* LDRD requires alignment; double-check that. */ - if (get_alignment_bits(opc) >= MO_64 - && (datalo & 1) == 0 && datahi == datalo + 1) { + if (get_alignment_bits(opc) >= MO_64) { /* * Rm (the second address op) must not overlap Rt or Rt + 1. * Since datalo is aligned, we can simplify the test via alignment. @@ -1750,9 +1752,11 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo, tcg_out_ld32_12(s, COND_AL, datalo, addrlo, 0); break; case MO_UQ: + /* We used pair allocation for datalo, so already should be aligned. */ + tcg_debug_assert((datalo & 1) == 0); + tcg_debug_assert(datahi == datalo + 1); /* LDRD requires alignment; double-check that. */ - if (get_alignment_bits(opc) >= MO_64 - && (datalo & 1) == 0 && datahi == datalo + 1) { + if (get_alignment_bits(opc) >= MO_64) { tcg_out_ldrd_8(s, COND_AL, datalo, addrlo, 0); } else if (datalo == addrlo) { tcg_out_ld32_12(s, COND_AL, datahi, addrlo, 4); @@ -1834,9 +1838,11 @@ static void tcg_out_qemu_st_index(TCGContext *s, ARMCond cond, MemOp opc, tcg_out_st32_r(s, cond, datalo, addrlo, addend); break; case MO_64: + /* We used pair allocation for datalo, so already should be aligned. */ + tcg_debug_assert((datalo & 1) == 0); + tcg_debug_assert(datahi == datalo + 1); /* STRD requires alignment; double-check that. */ - if (get_alignment_bits(opc) >= MO_64 - && (datalo & 1) == 0 && datahi == datalo + 1) { + if (get_alignment_bits(opc) >= MO_64) { tcg_out_strd_r(s, cond, datalo, addrlo, addend); } else if (scratch_addend) { tcg_out_st32_rwb(s, cond, datalo, addend, addrlo); @@ -1871,9 +1877,11 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, tcg_out_st32_12(s, COND_AL, datalo, addrlo, 0); break; case MO_64: + /* We used pair allocation for datalo, so already should be aligned. */ + tcg_debug_assert((datalo & 1) == 0); + tcg_debug_assert(datahi == datalo + 1); /* STRD requires alignment; double-check that. */ - if (get_alignment_bits(opc) >= MO_64 - && (datalo & 1) == 0 && datahi == datalo + 1) { + if (get_alignment_bits(opc) >= MO_64) { tcg_out_strd_8(s, COND_AL, datalo, addrlo, 0); } else { tcg_out_st32_12(s, COND_AL, datalo, addrlo, 0); @@ -2372,11 +2380,11 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_qemu_ld_i32: return TARGET_LONG_BITS == 32 ? C_O1_I1(r, l) : C_O1_I2(r, l, l); case INDEX_op_qemu_ld_i64: - return TARGET_LONG_BITS == 32 ? C_O2_I1(r, r, l) : C_O2_I2(r, r, l, l); + return TARGET_LONG_BITS == 32 ? C_O2_I1(e, p, l) : C_O2_I2(e, p, l, l); case INDEX_op_qemu_st_i32: return TARGET_LONG_BITS == 32 ? C_O0_I2(s, s) : C_O0_I3(s, s, s); case INDEX_op_qemu_st_i64: - return TARGET_LONG_BITS == 32 ? C_O0_I3(s, s, s) : C_O0_I4(s, s, s, s); + return TARGET_LONG_BITS == 32 ? C_O0_I3(S, p, s) : C_O0_I4(S, p, s, s); case INDEX_op_st_vec: return C_O0_I2(w, r); From ffe98631b36ebb39a0478501e271e11a5feeb15f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 29 Jul 2022 10:21:40 -0700 Subject: [PATCH 202/814] common-user/host/ppc: Implement safe-syscall.inc.S Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Message-Id: <20220729172141.1789105-2-richard.henderson@linaro.org> --- common-user/host/ppc/safe-syscall.inc.S | 107 ++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 common-user/host/ppc/safe-syscall.inc.S diff --git a/common-user/host/ppc/safe-syscall.inc.S b/common-user/host/ppc/safe-syscall.inc.S new file mode 100644 index 0000000000..0851f6c0b8 --- /dev/null +++ b/common-user/host/ppc/safe-syscall.inc.S @@ -0,0 +1,107 @@ +/* + * safe-syscall.inc.S : host-specific assembly fragment + * to handle signals occurring at the same time as system calls. + * This is intended to be included by common-user/safe-syscall.S + * + * Copyright (C) 2022 Linaro, Ltd. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Standardize on the _CALL_FOO symbols used by GCC: + * Apple XCode does not define _CALL_DARWIN. + * Clang defines _CALL_ELF (64-bit) but not _CALL_SYSV (32-bit). + */ +#if !defined(_CALL_SYSV) && \ + !defined(_CALL_DARWIN) && \ + !defined(_CALL_AIX) && \ + !defined(_CALL_ELF) +# if defined(__APPLE__) +# define _CALL_DARWIN +# elif defined(__ELF__) && TCG_TARGET_REG_BITS == 32 +# define _CALL_SYSV +# else +# error "Unknown ABI" +# endif +#endif + +#ifndef _CALL_SYSV +# error "Unsupported ABI" +#endif + + + .global safe_syscall_base + .global safe_syscall_start + .global safe_syscall_end + .type safe_syscall_base, @function + + .text + + /* + * This is the entry point for making a system call. The calling + * convention here is that of a C varargs function with the + * first argument an 'int *' to the signal_pending flag, the + * second one the system call number (as a 'long'), and all further + * arguments being syscall arguments (also 'long'). + */ +safe_syscall_base: + .cfi_startproc + stwu 1, -8(1) + .cfi_def_cfa_offset 8 + stw 30, 4(1) + .cfi_offset 30, -4 + + /* + * We enter with r3 == &signal_pending + * r4 == syscall number + * r5 ... r10 == syscall arguments + * and return the result in r3 + * and the syscall instruction needs + * r0 == syscall number + * r3 ... r8 == syscall arguments + * and returns the result in r3 + * Shuffle everything around appropriately. + */ + mr 30, 3 /* signal_pending */ + mr 0, 4 /* syscall number */ + mr 3, 5 /* syscall arguments */ + mr 4, 6 + mr 5, 7 + mr 6, 8 + mr 7, 9 + mr 8, 10 + + /* + * This next sequence of code works in conjunction with the + * rewind_if_safe_syscall_function(). If a signal is taken + * and the interrupted PC is anywhere between 'safe_syscall_start' + * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. + * The code sequence must therefore be able to cope with this, and + * the syscall instruction must be the final one in the sequence. + */ +safe_syscall_start: + /* if signal_pending is non-zero, don't do the call */ + lwz 12, 0(30) + cmpwi 0, 12, 0 + bne- 2f + sc +safe_syscall_end: + /* code path when we did execute the syscall */ + lwz 30, 4(1) /* restore r30 */ + addi 1, 1, 8 /* restore stack */ + .cfi_restore 30 + .cfi_def_cfa_offset 0 + bnslr+ /* return on success */ + b safe_syscall_set_errno_tail + + /* code path when we didn't execute the syscall */ +2: lwz 30, 4(1) + addi 1, 1, 8 + addi 3, 0, QEMU_ERESTARTSYS + b safe_syscall_set_errno_tail + + .cfi_endproc + + .size safe_syscall_base, .-safe_syscall_base From 2466bb3b083f965ef1ec12368c07e7d1e2f0b4c4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 29 Jul 2022 10:21:41 -0700 Subject: [PATCH 203/814] linux-user: Implment host/ppc/host-signal.h This commit re-enables ppc32 as a linux-user host, as existance of the directory is noted by configure. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1097 Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Message-Id: <20220729172141.1789105-3-richard.henderson@linaro.org> --- linux-user/include/host/ppc/host-signal.h | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 linux-user/include/host/ppc/host-signal.h diff --git a/linux-user/include/host/ppc/host-signal.h b/linux-user/include/host/ppc/host-signal.h new file mode 100644 index 0000000000..de25c803f5 --- /dev/null +++ b/linux-user/include/host/ppc/host-signal.h @@ -0,0 +1,39 @@ +/* + * host-signal.h: signal info dependent on the host architecture + * + * Copyright (c) 2022 Linaro Ltd. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef PPC_HOST_SIGNAL_H +#define PPC_HOST_SIGNAL_H + +#include + +/* The third argument to a SA_SIGINFO handler is ucontext_t. */ +typedef ucontext_t host_sigcontext; + +static inline uintptr_t host_signal_pc(host_sigcontext *uc) +{ + return uc->uc_mcontext.regs->nip; +} + +static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc) +{ + uc->uc_mcontext.regs->nip = pc; +} + +static inline void *host_signal_mask(host_sigcontext *uc) +{ + return &uc->uc_sigmask; +} + +static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) +{ + return uc->uc_mcontext.regs->trap != 0x400 + && (uc->uc_mcontext.regs->dsisr & 0x02000000); +} + +#endif From 6aa89be5c5ff9a534280b06fad9b01604e2155cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Jan 2023 06:46:16 -1000 Subject: [PATCH 204/814] tcg: Mark tcg helpers noinline to avoid an issue with LTO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marking helpers __attribute__((noinline)) prevents an issue with GCC's ipa-split pass under --enable-lto. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1454 Reviewed-by: Philippe Mathieu-Daudé Tested-by: Idan Horowitz Signed-off-by: Richard Henderson --- include/exec/helper-proto.h | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h index c4b1bda632..7a3f04b58c 100644 --- a/include/exec/helper-proto.h +++ b/include/exec/helper-proto.h @@ -6,34 +6,49 @@ #include "exec/helper-head.h" +/* + * Work around an issue with --enable-lto, in which GCC's ipa-split pass + * decides to split out the noreturn code paths that raise an exception, + * taking the __builtin_return_address() along into the new function, + * where it no longer computes a value that returns to TCG generated code. + * Despite the name, the noinline attribute affects splitter, so this + * prevents the optimization in question. Given that helpers should not + * otherwise be called directly, this should have any other visible effect. + * + * See https://gitlab.com/qemu-project/qemu/-/issues/1454 + */ +#define DEF_HELPER_ATTR __attribute__((noinline)) + #define DEF_HELPER_FLAGS_0(name, flags, ret) \ -dh_ctype(ret) HELPER(name) (void); +dh_ctype(ret) HELPER(name) (void) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \ -dh_ctype(ret) HELPER(name) (dh_ctype(t1)); +dh_ctype(ret) HELPER(name) (dh_ctype(t1)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ -dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)); +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \ -dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3)); +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), \ + dh_ctype(t3)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ - dh_ctype(t4)); + dh_ctype(t4)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ - dh_ctype(t4), dh_ctype(t5)); + dh_ctype(t4), dh_ctype(t5)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ - dh_ctype(t4), dh_ctype(t5), dh_ctype(t6)); + dh_ctype(t4), dh_ctype(t5), \ + dh_ctype(t6)) DEF_HELPER_ATTR; #define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7) \ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(t4), dh_ctype(t5), dh_ctype(t6), \ - dh_ctype(t7)); + dh_ctype(t7)) DEF_HELPER_ATTR; #define IN_HELPER_PROTO @@ -51,5 +66,6 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ #undef DEF_HELPER_FLAGS_5 #undef DEF_HELPER_FLAGS_6 #undef DEF_HELPER_FLAGS_7 +#undef DEF_HELPER_ATTR #endif /* HELPER_PROTO_H */ From 2e0d91513deb9bf0e5a1b2e0f574d999df3ebd99 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Nov 2022 16:22:09 -0800 Subject: [PATCH 205/814] target/loongarch: Enable the disassembler for host tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse the decodetree based disassembler from target/loongarch/ for tcg/loongarch64/. The generation of decode-insns.c.inc into ./libcommon.fa.p/ could eventually result in conflict, if any other host requires the same trick, but this is good enough for now. Reviewed-by: WANG Xuerui Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- disas.c | 2 ++ target/loongarch/meson.build | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/disas.c b/disas.c index 3b31315f40..b087c12c47 100644 --- a/disas.c +++ b/disas.c @@ -198,6 +198,8 @@ static void initialize_debug_host(CPUDebug *s) s->info.cap_insn_split = 6; #elif defined(__hppa__) s->info.print_insn = print_insn_hppa; +#elif defined(__loongarch__) + s->info.print_insn = print_insn_loongarch; #endif } diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build index 6376f9e84b..690633969f 100644 --- a/target/loongarch/meson.build +++ b/target/loongarch/meson.build @@ -3,7 +3,6 @@ gen = decodetree.process('insns.decode') loongarch_ss = ss.source_set() loongarch_ss.add(files( 'cpu.c', - 'disas.c', )) loongarch_tcg_ss = ss.source_set() loongarch_tcg_ss.add(gen) @@ -24,6 +23,8 @@ loongarch_softmmu_ss.add(files( 'iocsr_helper.c', )) +common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: [files('disas.c'), gen]) + loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) target_arch += {'loongarch': loongarch_ss} From c2b618a8c1acb899b56eb8b2f1354da1f69474ea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 17 Jan 2023 14:32:38 -1000 Subject: [PATCH 206/814] target/loongarch: Disassemble jirl properly While jirl shares the same instruction format as bne etc, it is not assembled the same. In particular, rd is printed first not second and the immediate is not pc-relative. Decode into the arg_rr_i structure, which prints correctly. This changes the "offs" member to "imm", to update translate. Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- target/loongarch/disas.c | 2 +- target/loongarch/insn_trans/trans_branch.c.inc | 2 +- target/loongarch/insns.decode | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 858dfcc53a..7cffd853ec 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -628,7 +628,7 @@ INSN(beqz, r_offs) INSN(bnez, r_offs) INSN(bceqz, c_offs) INSN(bcnez, c_offs) -INSN(jirl, rr_offs) +INSN(jirl, rr_i) INSN(b, offs) INSN(bl, offs) INSN(beq, rr_offs) diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index 65dbdff41e..a860f7e733 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -23,7 +23,7 @@ static bool trans_jirl(DisasContext *ctx, arg_jirl *a) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); - tcg_gen_addi_tl(cpu_pc, src1, a->offs); + tcg_gen_addi_tl(cpu_pc, src1, a->imm); tcg_gen_movi_tl(dest, ctx->base.pc_next + 4); gen_set_gpr(a->rd, dest, EXT_NONE); tcg_gen_lookup_and_goto_ptr(); diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 3fdc6e148c..de7b8f0f3c 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -67,6 +67,7 @@ @rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i @rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2 @rr_i16 .... .. imm:s16 rj:5 rd:5 &rr_i +@rr_i16s2 .... .. ................ rj:5 rd:5 &rr_i imm=%offs16 @hint_r_i12 .... ...... imm:s12 rj:5 hint:5 &hint_r_i @rrr_sa2p1 .... ........ ... .. rk:5 rj:5 rd:5 &rrr_sa sa=%sa2p1 @rrr_sa2 .... ........ ... sa:2 rk:5 rj:5 rd:5 &rrr_sa @@ -444,7 +445,7 @@ beqz 0100 00 ................ ..... ..... @r_offs21 bnez 0100 01 ................ ..... ..... @r_offs21 bceqz 0100 10 ................ 00 ... ..... @c_offs21 bcnez 0100 10 ................ 01 ... ..... @c_offs21 -jirl 0100 11 ................ ..... ..... @rr_offs16 +jirl 0100 11 ................ ..... ..... @rr_i16s2 b 0101 00 .......................... @offs26 bl 0101 01 .......................... @offs26 beq 0101 10 ................ ..... ..... @rr_offs16 From 69c9a5cfbedcaebfb0deddb5278a289629b78af5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 17 Jan 2023 14:54:50 -1000 Subject: [PATCH 207/814] target/loongarch: Disassemble pcadd* addresses Print both the raw field and the resolved pc-relative address, as we do for branches. Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- target/loongarch/disas.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c index 7cffd853ec..2e93e77e0d 100644 --- a/target/loongarch/disas.c +++ b/target/loongarch/disas.c @@ -519,10 +519,6 @@ INSN(fsel, fffc) INSN(addu16i_d, rr_i) INSN(lu12i_w, r_i) INSN(lu32i_d, r_i) -INSN(pcaddi, r_i) -INSN(pcalau12i, r_i) -INSN(pcaddu12i, r_i) -INSN(pcaddu18i, r_i) INSN(ll_w, rr_i) INSN(sc_w, rr_i) INSN(ll_d, rr_i) @@ -755,3 +751,36 @@ static bool trans_fcmp_cond_##suffix(DisasContext *ctx, \ FCMP_INSN(s) FCMP_INSN(d) + +#define PCADD_INSN(name) \ +static bool trans_##name(DisasContext *ctx, arg_##name *a) \ +{ \ + output(ctx, #name, "r%d, %d # 0x%" PRIx64, \ + a->rd, a->imm, gen_##name(ctx->pc, a->imm)); \ + return true; \ +} + +static uint64_t gen_pcaddi(uint64_t pc, int imm) +{ + return pc + (imm << 2); +} + +static uint64_t gen_pcalau12i(uint64_t pc, int imm) +{ + return (pc + (imm << 12)) & ~0xfff; +} + +static uint64_t gen_pcaddu12i(uint64_t pc, int imm) +{ + return pc + (imm << 12); +} + +static uint64_t gen_pcaddu18i(uint64_t pc, int imm) +{ + return pc + ((uint64_t)(imm) << 18); +} + +PCADD_INSN(pcaddi) +PCADD_INSN(pcalau12i) +PCADD_INSN(pcaddu12i) +PCADD_INSN(pcaddu18i) From 3fe7e36b44c0eca9b1f54060c0265c721e7f6d81 Mon Sep 17 00:00:00 2001 From: Rui Wang Date: Mon, 7 Nov 2022 22:47:13 +0800 Subject: [PATCH 208/814] tcg/loongarch64: Optimize immediate loading diff: Imm Before After 0000000000000000 addi.w rd, zero, 0 addi.w rd, zero, 0 lu52i.d rd, zero, 0 00000000fffff800 lu12i.w rd, -1 addi.w rd, zero, -2048 ori rd, rd, 2048 lu32i.d rd, 0 lu32i.d rd, 0 Reviewed-by: WANG Xuerui Signed-off-by: Rui Wang Message-Id: <20221107144713.845550-1-wangrui@loongson.cn> Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 35 +++++++++++--------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 3174557ce3..428f3abd71 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -274,16 +274,6 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) return true; } -static bool imm_part_needs_loading(bool high_bits_are_ones, - tcg_target_long part) -{ - if (high_bits_are_ones) { - return part != -1; - } else { - return part != 0; - } -} - /* Loads a 32-bit immediate into rd, sign-extended. */ static void tcg_out_movi_i32(TCGContext *s, TCGReg rd, int32_t val) { @@ -291,16 +281,16 @@ static void tcg_out_movi_i32(TCGContext *s, TCGReg rd, int32_t val) tcg_target_long hi12 = sextreg(val, 12, 20); /* Single-instruction cases. */ - if (lo == val) { - /* val fits in simm12: addi.w rd, zero, val */ - tcg_out_opc_addi_w(s, rd, TCG_REG_ZERO, val); - return; - } - if (0x800 <= val && val <= 0xfff) { + if (hi12 == 0) { /* val fits in uimm12: ori rd, zero, val */ tcg_out_opc_ori(s, rd, TCG_REG_ZERO, val); return; } + if (hi12 == sextreg(lo, 12, 20)) { + /* val fits in simm12: addi.w rd, zero, val */ + tcg_out_opc_addi_w(s, rd, TCG_REG_ZERO, val); + return; + } /* High bits must be set; load with lu12i.w + optional ori. */ tcg_out_opc_lu12i_w(s, rd, hi12); @@ -334,8 +324,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, intptr_t pc_offset; tcg_target_long val_lo, val_hi, pc_hi, offset_hi; - tcg_target_long hi32, hi52; - bool rd_high_bits_are_ones; + tcg_target_long hi12, hi32, hi52; /* Value fits in signed i32. */ if (type == TCG_TYPE_I32 || val == (int32_t)val) { @@ -366,25 +355,25 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, return; } + hi12 = sextreg(val, 12, 20); hi32 = sextreg(val, 32, 20); hi52 = sextreg(val, 52, 12); /* Single cu52i.d case. */ - if (ctz64(val) >= 52) { + if ((hi52 != 0) && (ctz64(val) >= 52)) { tcg_out_opc_cu52i_d(s, rd, TCG_REG_ZERO, hi52); return; } /* Slow path. Initialize the low 32 bits, then concat high bits. */ tcg_out_movi_i32(s, rd, val); - rd_high_bits_are_ones = (int32_t)val < 0; - if (imm_part_needs_loading(rd_high_bits_are_ones, hi32)) { + /* Load hi32 and hi52 explicitly when they are unexpected values. */ + if (hi32 != sextreg(hi12, 20, 20)) { tcg_out_opc_cu32i_d(s, rd, hi32); - rd_high_bits_are_ones = hi32 < 0; } - if (imm_part_needs_loading(rd_high_bits_are_ones, hi52)) { + if (hi52 != sextreg(hi32, 20, 12)) { tcg_out_opc_cu52i_d(s, rd, rd, hi52); } } From 76baa33a10abaa327874d9dc4b284992e5e420c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Nov 2022 21:57:31 -0800 Subject: [PATCH 209/814] tcg/loongarch64: Update tcg-insn-defs.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerate with ADDU16I included: $ cd loongarch-opcodes/scripts/go $ go run ./genqemutcgdefs > $QEMU/tcg/loongarch64/tcg-insn-defs.c.inc Reviewed-by: WANG Xuerui Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-insn-defs.c.inc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tcg/loongarch64/tcg-insn-defs.c.inc b/tcg/loongarch64/tcg-insn-defs.c.inc index d162571856..b5bb0c5e73 100644 --- a/tcg/loongarch64/tcg-insn-defs.c.inc +++ b/tcg/loongarch64/tcg-insn-defs.c.inc @@ -4,7 +4,7 @@ * * This file is auto-generated by genqemutcgdefs from * https://github.com/loongson-community/loongarch-opcodes, - * from commit 961f0c60f5b63e574d785995600c71ad5413fdc4. + * from commit 25ca7effe9d88101c1cf96c4005423643386d81f. * DO NOT EDIT. */ @@ -74,6 +74,7 @@ typedef enum { OPC_ANDI = 0x03400000, OPC_ORI = 0x03800000, OPC_XORI = 0x03c00000, + OPC_ADDU16I_D = 0x10000000, OPC_LU12I_W = 0x14000000, OPC_CU32I_D = 0x16000000, OPC_PCADDU2I = 0x18000000, @@ -710,6 +711,13 @@ tcg_out_opc_xori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) tcg_out32(s, encode_djuk12_insn(OPC_XORI, d, j, uk12)); } +/* Emits the `addu16i.d d, j, sk16` instruction. */ +static void __attribute__((unused)) +tcg_out_opc_addu16i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +{ + tcg_out32(s, encode_djsk16_insn(OPC_ADDU16I_D, d, j, sk16)); +} + /* Emits the `lu12i.w d, sj20` instruction. */ static void __attribute__((unused)) tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, int32_t sj20) From 0e95be93c1200ded3296654c96cb34ae13beab6d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Nov 2022 22:46:52 -0800 Subject: [PATCH 210/814] tcg/loongarch64: Introduce tcg_out_addi Adjust the constraints to allow any int32_t for immediate addition. Split immediate adds into addu16i + addi, which covers quite a lot of the immediate space. For the hole in the middle, load the constant into TMP0 instead. Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target-con-set.h | 4 +- tcg/loongarch64/tcg-target-con-str.h | 2 +- tcg/loongarch64/tcg-target.c.inc | 57 ++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index 349c672687..7b5a7a3f5d 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -23,9 +23,11 @@ C_O1_I1(r, L) C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) +C_O1_I2(r, r, rJ) C_O1_I2(r, r, rU) C_O1_I2(r, r, rW) C_O1_I2(r, r, rZ) C_O1_I2(r, 0, rZ) -C_O1_I2(r, rZ, rN) +C_O1_I2(r, rZ, ri) +C_O1_I2(r, rZ, rJ) C_O1_I2(r, rZ, rZ) diff --git a/tcg/loongarch64/tcg-target-con-str.h b/tcg/loongarch64/tcg-target-con-str.h index c3986a4fd4..541ff47fa9 100644 --- a/tcg/loongarch64/tcg-target-con-str.h +++ b/tcg/loongarch64/tcg-target-con-str.h @@ -21,7 +21,7 @@ REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) * CONST(letter, TCG_CT_CONST_* bit set) */ CONST('I', TCG_CT_CONST_S12) -CONST('N', TCG_CT_CONST_N12) +CONST('J', TCG_CT_CONST_S32) CONST('U', TCG_CT_CONST_U12) CONST('Z', TCG_CT_CONST_ZERO) CONST('C', TCG_CT_CONST_C12) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 428f3abd71..8cc6c5eec2 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -126,7 +126,7 @@ static const int tcg_target_call_oarg_regs[] = { #define TCG_CT_CONST_ZERO 0x100 #define TCG_CT_CONST_S12 0x200 -#define TCG_CT_CONST_N12 0x400 +#define TCG_CT_CONST_S32 0x400 #define TCG_CT_CONST_U12 0x800 #define TCG_CT_CONST_C12 0x1000 #define TCG_CT_CONST_WSZ 0x2000 @@ -161,7 +161,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) { return true; } - if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) { + if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) { return true; } if ((ct & TCG_CT_CONST_U12) && val >= 0 && val <= 0xfff) { @@ -378,6 +378,45 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, } } +static void tcg_out_addi(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rs, tcg_target_long imm) +{ + tcg_target_long lo12 = sextreg(imm, 0, 12); + tcg_target_long hi16 = sextreg(imm - lo12, 16, 16); + + /* + * Note that there's a hole in between hi16 and lo12: + * + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * ...+-------------------------------+-------+-----------------------+ + * | hi16 | | lo12 | + * ...+-------------------------------+-------+-----------------------+ + * + * For bits within that hole, it's more efficient to use LU12I and ADD. + */ + if (imm == (hi16 << 16) + lo12) { + if (hi16) { + tcg_out_opc_addu16i_d(s, rd, rs, hi16); + rs = rd; + } + if (type == TCG_TYPE_I32) { + tcg_out_opc_addi_w(s, rd, rs, lo12); + } else if (lo12) { + tcg_out_opc_addi_d(s, rd, rs, lo12); + } else { + tcg_out_mov(s, type, rd, rs); + } + } else { + tcg_out_movi(s, type, TCG_REG_TMP0, imm); + if (type == TCG_TYPE_I32) { + tcg_out_opc_add_w(s, rd, rs, TCG_REG_TMP0); + } else { + tcg_out_opc_add_d(s, rd, rs, TCG_REG_TMP0); + } + } +} + static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) { tcg_out_opc_andi(s, ret, arg, 0xff); @@ -1350,14 +1389,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_add_i32: if (c2) { - tcg_out_opc_addi_w(s, a0, a1, a2); + 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_opc_addi_d(s, a0, a1, a2); + tcg_out_addi(s, TCG_TYPE_I64, a0, a1, a2); } else { tcg_out_opc_add_d(s, a0, a1, a2); } @@ -1365,14 +1404,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_sub_i32: if (c2) { - tcg_out_opc_addi_w(s, a0, a1, -a2); + 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_opc_addi_d(s, a0, a1, -a2); + tcg_out_addi(s, TCG_TYPE_I64, a0, a1, -a2); } else { tcg_out_opc_sub_d(s, a0, a1, a2); } @@ -1586,8 +1625,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) 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, rI); + return C_O1_I2(r, r, rJ); case INDEX_op_and_i32: case INDEX_op_and_i64: @@ -1616,8 +1656,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) return C_O1_I2(r, 0, rZ); case INDEX_op_sub_i32: + return C_O1_I2(r, rZ, ri); case INDEX_op_sub_i64: - return C_O1_I2(r, rZ, rN); + return C_O1_I2(r, rZ, rJ); case INDEX_op_mul_i32: case INDEX_op_mul_i64: From 21af16198425f1eaf5086e1406f22561da05e259 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Nov 2022 07:08:12 -0800 Subject: [PATCH 211/814] tcg/loongarch64: Improve setcond expansion Split out a helper function, tcg_out_setcond_int, which does not always produce the complete boolean result, but returns a set of flags to do so. Accept all int32_t as constant input, so that LE/GT can adjust the constant to LT. Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 165 +++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 50 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 8cc6c5eec2..ccc1c0f392 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -469,64 +469,131 @@ static void tcg_out_clzctz(TCGContext *s, LoongArchInsn opc, tcg_out_opc_or(s, a0, TCG_REG_TMP0, a0); } -static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg arg1, TCGReg arg2, bool c2) -{ - TCGReg tmp; +#define SETCOND_INV TCG_TARGET_NB_REGS +#define SETCOND_NEZ (SETCOND_INV << 1) +#define SETCOND_FLAGS (SETCOND_INV | SETCOND_NEZ) - if (c2) { - tcg_debug_assert(arg2 == 0); +static int tcg_out_setcond_int(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg arg1, tcg_target_long arg2, bool c2) +{ + int flags = 0; + + switch (cond) { + case TCG_COND_EQ: /* -> NE */ + case TCG_COND_GE: /* -> LT */ + case TCG_COND_GEU: /* -> LTU */ + case TCG_COND_GT: /* -> LE */ + case TCG_COND_GTU: /* -> LEU */ + cond = tcg_invert_cond(cond); + flags ^= SETCOND_INV; + break; + default: + break; } switch (cond) { - case TCG_COND_EQ: - if (c2) { - tmp = arg1; - } else { - tcg_out_opc_sub_d(s, ret, arg1, arg2); - tmp = ret; - } - tcg_out_opc_sltui(s, ret, tmp, 1); - break; - case TCG_COND_NE: - if (c2) { - tmp = arg1; - } else { - tcg_out_opc_sub_d(s, ret, arg1, arg2); - tmp = ret; - } - tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); - break; - case TCG_COND_LT: - tcg_out_opc_slt(s, ret, arg1, arg2); - break; - case TCG_COND_GE: - tcg_out_opc_slt(s, ret, arg1, arg2); - tcg_out_opc_xori(s, ret, ret, 1); - break; case TCG_COND_LE: - tcg_out_setcond(s, TCG_COND_GE, ret, arg2, arg1, false); - break; - case TCG_COND_GT: - tcg_out_setcond(s, TCG_COND_LT, ret, arg2, arg1, false); - break; - case TCG_COND_LTU: - tcg_out_opc_sltu(s, ret, arg1, arg2); - break; - case TCG_COND_GEU: - tcg_out_opc_sltu(s, ret, arg1, arg2); - tcg_out_opc_xori(s, ret, ret, 1); - break; case TCG_COND_LEU: - tcg_out_setcond(s, TCG_COND_GEU, ret, arg2, arg1, false); + /* + * If we have a constant input, the most efficient way to implement + * LE is by adding 1 and using LT. Watch out for wrap around for LEU. + * We don't need to care for this for LE because the constant input + * is still constrained to int32_t, and INT32_MAX+1 is representable + * in the 64-bit temporary register. + */ + if (c2) { + if (cond == TCG_COND_LEU) { + /* unsigned <= -1 is true */ + if (arg2 == -1) { + tcg_out_movi(s, TCG_TYPE_REG, ret, !(flags & SETCOND_INV)); + return ret; + } + cond = TCG_COND_LTU; + } else { + cond = TCG_COND_LT; + } + arg2 += 1; + } else { + TCGReg tmp = arg2; + arg2 = arg1; + arg1 = tmp; + cond = tcg_swap_cond(cond); /* LE -> GE */ + cond = tcg_invert_cond(cond); /* GE -> LT */ + flags ^= SETCOND_INV; + } break; - case TCG_COND_GTU: - tcg_out_setcond(s, TCG_COND_LTU, ret, arg2, arg1, false); + default: break; + } + + switch (cond) { + case TCG_COND_NE: + flags |= SETCOND_NEZ; + if (!c2) { + tcg_out_opc_xor(s, ret, arg1, arg2); + } else if (arg2 == 0) { + ret = arg1; + } else if (arg2 >= 0 && arg2 <= 0xfff) { + tcg_out_opc_xori(s, ret, arg1, arg2); + } else { + tcg_out_addi(s, TCG_TYPE_REG, ret, arg1, -arg2); + } + break; + + case TCG_COND_LT: + case TCG_COND_LTU: + if (c2) { + if (arg2 >= -0x800 && arg2 <= 0x7ff) { + if (cond == TCG_COND_LT) { + tcg_out_opc_slti(s, ret, arg1, arg2); + } else { + tcg_out_opc_sltui(s, ret, arg1, arg2); + } + break; + } + tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP0, arg2); + arg2 = TCG_REG_TMP0; + } + if (cond == TCG_COND_LT) { + tcg_out_opc_slt(s, ret, arg1, arg2); + } else { + tcg_out_opc_sltu(s, ret, arg1, arg2); + } + break; + default: g_assert_not_reached(); break; } + + return ret | flags; +} + +static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg arg1, tcg_target_long arg2, bool c2) +{ + int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2, c2); + + if (tmpflags != ret) { + TCGReg tmp = tmpflags & ~SETCOND_FLAGS; + + switch (tmpflags & SETCOND_FLAGS) { + case SETCOND_INV: + /* Intermediate result is boolean: simply invert. */ + tcg_out_opc_xori(s, ret, tmp, 1); + break; + case SETCOND_NEZ: + /* Intermediate result is zero/non-zero: test != 0. */ + tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); + break; + case SETCOND_NEZ | SETCOND_INV: + /* Intermediate result is zero/non-zero: test == 0. */ + tcg_out_opc_sltui(s, ret, tmp, 1); + break; + default: + g_assert_not_reached(); + } + } } /* @@ -1646,18 +1713,16 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_ctz_i64: return C_O1_I2(r, r, rW); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - return C_O1_I2(r, r, rZ); - 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_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); case INDEX_op_mul_i32: From 7bc76a4c2e996add45291ed75ab417314a87427c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Nov 2022 08:46:19 -0800 Subject: [PATCH 212/814] tcg/loongarch64: Implement movcond Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target-con-set.h | 1 + tcg/loongarch64/tcg-target.c.inc | 33 ++++++++++++++++++++++++++++ tcg/loongarch64/tcg-target.h | 4 ++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index 7b5a7a3f5d..172c107289 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -31,3 +31,4 @@ 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_I4(r, rZ, rJ, rZ, rZ) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index ccc1c0f392..29d75c80eb 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -596,6 +596,30 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg c1, tcg_target_long c2, bool const2, + TCGReg v1, TCGReg v2) +{ + int tmpflags = tcg_out_setcond_int(s, cond, TCG_REG_TMP0, c1, c2, const2); + TCGReg t; + + /* Standardize the test below to t != 0. */ + if (tmpflags & SETCOND_INV) { + t = v1, v1 = v2, v2 = t; + } + + t = tmpflags & ~SETCOND_FLAGS; + if (v1 == TCG_REG_ZERO) { + tcg_out_opc_masknez(s, ret, v2, t); + } else if (v2 == TCG_REG_ZERO) { + tcg_out_opc_maskeqz(s, ret, v1, t); + } else { + tcg_out_opc_masknez(s, TCG_REG_TMP2, v2, t); /* t ? 0 : v2 */ + tcg_out_opc_maskeqz(s, TCG_REG_TMP1, v1, t); /* t ? v1 : 0 */ + tcg_out_opc_or(s, ret, TCG_REG_TMP1, TCG_REG_TMP2); + } +} + /* * Branch helpers */ @@ -1538,6 +1562,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_setcond(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, 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); @@ -1741,6 +1770,10 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) 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); + default: g_assert_not_reached(); } diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 1c3e48d662..533a539ce9 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -97,7 +97,7 @@ typedef enum { #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL /* optional instructions */ -#define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_movcond_i32 1 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 @@ -133,7 +133,7 @@ typedef enum { #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ -#define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_movcond_i64 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 From 21199bfbef8b69305cf419e22a455e7a1923c4ba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Nov 2022 09:03:23 -0800 Subject: [PATCH 213/814] tcg/loongarch64: Use tcg_pcrel_diff in tcg_out_ldst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the w^x split into account when computing the pc-relative distance to an absolute pointer. Reviewed-by: WANG Xuerui Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 29d75c80eb..d6926bdb83 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -702,7 +702,7 @@ static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data, intptr_t imm12 = sextreg(offset, 0, 12); if (offset != imm12) { - intptr_t diff = offset - (uintptr_t)s->code_ptr; + intptr_t diff = tcg_pcrel_diff(s, (void *)offset); if (addr == TCG_REG_ZERO && diff == (int32_t)diff) { imm12 = sextreg(diff, 0, 12); From 709bcd7da3f6b4655d910634a0d520fa1439df38 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Nov 2022 11:02:20 -0800 Subject: [PATCH 214/814] tcg/loongarch64: Reorg goto_tb implementation The old implementation replaces two insns, swapping between b nop and pcaddu18i tmp, jirl zero, tmp, & 0xffff There is a race condition in which a thread could be stopped at the jirl, i.e. with the top of the address loaded, and when restarted we have re-linked to a different TB, so that the top half no longer matches the bottom half. Note that while we never directly re-link to a different TB, we can link, unlink, and link again all while the stopped thread remains stopped. The new implementation replaces only one insn, swapping between b and pcadd tmp, falling through to load the address from tmp, and branch. Reviewed-by: WANG Xuerui Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 72 ++++++++++++++------------------ tcg/loongarch64/tcg-target.h | 7 +--- 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index d6926bdb83..ce4a153887 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1151,37 +1151,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) #endif } -/* LoongArch uses `andi zero, zero, 0` as NOP. */ -#define NOP OPC_ANDI -static void tcg_out_nop(TCGContext *s) -{ - tcg_out32(s, NOP); -} - -void tb_target_set_jmp_target(const TranslationBlock *tb, int n, - uintptr_t jmp_rx, uintptr_t jmp_rw) -{ - tcg_insn_unit i1, i2; - ptrdiff_t upper, lower; - uintptr_t addr = tb->jmp_target_addr[n]; - ptrdiff_t offset = (ptrdiff_t)(addr - jmp_rx) >> 2; - - if (offset == sextreg(offset, 0, 26)) { - i1 = encode_sd10k16_insn(OPC_B, offset); - i2 = NOP; - } else { - tcg_debug_assert(offset == sextreg(offset, 0, 36)); - lower = (int16_t)offset; - upper = (offset - lower) >> 16; - - i1 = encode_dsj20_insn(OPC_PCADDU18I, TCG_REG_TMP0, upper); - i2 = encode_djsk16_insn(OPC_JIRL, TCG_REG_ZERO, TCG_REG_TMP0, lower); - } - uint64_t pair = ((uint64_t)i2 << 32) | i1; - qatomic_set((uint64_t *)jmp_rw, pair); - flush_idcache_range(jmp_rx, jmp_rw, 8); -} - /* * Entry-points */ @@ -1202,22 +1171,43 @@ static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) static void tcg_out_goto_tb(TCGContext *s, int which) { /* - * Ensure that patch area is 8-byte aligned so that an - * atomic write can be used to patch the target address. + * Direct branch, or load indirect address, to be patched + * by tb_target_set_jmp_target. Check indirect load offset + * in range early, regardless of direct branch distance, + * via assert within tcg_out_opc_pcaddu2i. */ - if ((uintptr_t)s->code_ptr & 7) { - tcg_out_nop(s); - } + uintptr_t i_addr = get_jmp_target_addr(s, which); + intptr_t i_disp = tcg_pcrel_diff(s, (void *)i_addr); + set_jmp_insn_offset(s, which); - /* - * actual branch destination will be patched by - * tb_target_set_jmp_target later - */ - tcg_out_opc_pcaddu18i(s, TCG_REG_TMP0, 0); + tcg_out_opc_pcaddu2i(s, TCG_REG_TMP0, i_disp >> 2); + + /* Finish the load and indirect branch. */ + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_TMP0, 0); tcg_out_opc_jirl(s, TCG_REG_ZERO, TCG_REG_TMP0, 0); set_jmp_reset_offset(s, which); } +void tb_target_set_jmp_target(const TranslationBlock *tb, int n, + uintptr_t jmp_rx, uintptr_t jmp_rw) +{ + uintptr_t d_addr = tb->jmp_target_addr[n]; + ptrdiff_t d_disp = (ptrdiff_t)(d_addr - jmp_rx) >> 2; + tcg_insn_unit insn; + + /* Either directly branch, or load slot address for indirect branch. */ + if (d_disp == sextreg(d_disp, 0, 26)) { + insn = encode_sd10k16_insn(OPC_B, d_disp); + } else { + uintptr_t i_addr = (uintptr_t)&tb->jmp_target_addr[n]; + intptr_t i_disp = i_addr - jmp_rx; + insn = encode_dsj20_insn(OPC_PCADDU2I, TCG_REG_TMP0, i_disp >> 2); + } + + qatomic_set((tcg_insn_unit *)jmp_rw, insn); + flush_idcache_range(jmp_rx, jmp_rw, 4); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 533a539ce9..8b151e7f6f 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -42,11 +42,8 @@ #define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_NB_REGS 32 -/* - * PCADDU18I + JIRL sequence can give 20 + 16 + 2 = 38 bits - * signed offset, which is +/- 128 GiB. - */ -#define MAX_CODE_GEN_BUFFER_SIZE (128 * GiB) + +#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) typedef enum { TCG_REG_ZERO, From 724e6703b1823d34e485bc710dcff586c5ce120d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Jan 2023 12:46:01 +0100 Subject: [PATCH 215/814] tests/qemu-iotests/312: Mark "quorum" as required driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "quorum" is required by iotest 312 - if it is not compiled into the QEMU binary, the test fails. Thus list "quorum" as required driver so that the test gets skipped in case it is not available. Signed-off-by: Thomas Huth Message-Id: <20230104114601.269351-1-thuth@redhat.com> Reviewed-by: Alberto Garcia Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/312 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/312 b/tests/qemu-iotests/312 index 4139745f0e..0d9ea09a31 100755 --- a/tests/qemu-iotests/312 +++ b/tests/qemu-iotests/312 @@ -52,6 +52,7 @@ _supported_fmt qcow2 _supported_proto file _supported_os Linux _unsupported_imgopts cluster_size data_file +_require_drivers quorum echo echo '### Create all images' # three source (quorum), one destination From 95988739c73f76176327061824c603f85b072ff2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Jan 2023 12:28:50 +0100 Subject: [PATCH 216/814] tests/qemu-iotests/262: Check for availability of "blkverify" first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In downstream RHEL builds, we do not have "blkverify" enabled, so iotest 262 is currently failing there. Thus let's list "blkverify" as required item so that the test properly gets skipped instead if "blkverify" is missing. Signed-off-by: Thomas Huth Message-Id: <20230104112850.261480-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/262 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/262 b/tests/qemu-iotests/262 index 2294fd5ecb..a4a92de45a 100755 --- a/tests/qemu-iotests/262 +++ b/tests/qemu-iotests/262 @@ -25,7 +25,8 @@ import iotests import os iotests.script_initialize(supported_fmts=['qcow2'], - supported_platforms=['linux']) + supported_platforms=['linux'], + required_fmts=['blkverify']) with iotests.FilePath('img') as img_path, \ iotests.FilePath('mig_fifo') as fifo, \ From a4b15a8b9ef25b44fa92a4825312622600c1f37c Mon Sep 17 00:00:00 2001 From: Xiang Zheng Date: Tue, 20 Dec 2022 09:42:46 +0100 Subject: [PATCH 217/814] pflash: Only read non-zero parts of backend image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we fill the VIRT_FLASH memory space with two 64MB NOR images when using persistent UEFI variables on virt board. Actually we only use a very small(non-zero) part of the memory while the rest significant large(zero) part of memory is wasted. So this patch checks the block status and only writes the non-zero part into memory. This requires pflash devices to use sparse files for backends. Signed-off-by: Xiang Zheng [ kraxel: rebased to latest master ] Signed-off-by: Gerd Hoffmann Message-Id: <20221220084246.1984871-1-kraxel@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- hw/block/block.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/block/block.c b/hw/block/block.c index ddcef71f80..af0710e477 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -15,6 +15,40 @@ #include "qapi/error.h" #include "qapi/qapi-types-block.h" +/* + * Read the non-zeroes parts of @blk into @buf + * Reading all of the @blk is expensive if the zeroes parts of @blk + * is large enough. Therefore check the block status and only write + * the non-zeroes block into @buf. + * + * Return 0 on success, non-zero on error. + */ +static int blk_pread_nonzeroes(BlockBackend *blk, hwaddr size, void *buf) +{ + int ret; + int64_t bytes, offset = 0; + BlockDriverState *bs = blk_bs(blk); + + for (;;) { + bytes = MIN(size - offset, BDRV_REQUEST_MAX_SECTORS); + if (bytes <= 0) { + return 0; + } + ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL); + if (ret < 0) { + return ret; + } + if (!(ret & BDRV_BLOCK_ZERO)) { + ret = bdrv_pread(bs->file, offset, bytes, + (uint8_t *) buf + offset, 0); + if (ret < 0) { + return ret; + } + } + offset += bytes; + } +} + /* * Read the entire contents of @blk into @buf. * @blk's contents must be @size bytes, and @size must be at most @@ -54,7 +88,7 @@ bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, * block device and read only on demand. */ assert(size <= BDRV_REQUEST_MAX_BYTES); - ret = blk_pread(blk, 0, size, buf, 0); + ret = blk_pread_nonzeroes(blk, size, buf); if (ret < 0) { error_setg_errno(errp, -ret, "can't read block backend"); return false; From cbdbc47cee539ed1ef3e9a27adc47e26d1f921c6 Mon Sep 17 00:00:00 2001 From: Alberto Faria Date: Fri, 16 Dec 2022 12:07:57 +0100 Subject: [PATCH 218/814] coroutine: annotate coroutine_fn for libclang Clang has a generic __annotate__ attribute that can be used by static analyzers to understand properties of functions and analyze the control flow. Furthermore, unlike TSA annotations, the __annotate__ attribute applies to function pointers as well. As a first step towards static analysis of coroutine_fn markers, attach the attribute to the marker when compiling with clang. Signed-off-by: Alberto Faria Signed-off-by: Paolo Bonzini Message-Id: <20221216110758.559947-2-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/qemu/osdep.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index c850001408..d1be7bf8b9 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -171,7 +171,11 @@ extern "C" { * .... * } */ +#ifdef __clang__ +#define coroutine_fn __attribute__((__annotate__("coroutine_fn"))) +#else #define coroutine_fn +#endif /* * For mingw, as of v6.0.0, the function implementing the assert macro is From 0f3de970febd2c9b29dccecb63ca928c6802a101 Mon Sep 17 00:00:00 2001 From: Alberto Faria Date: Fri, 16 Dec 2022 12:07:58 +0100 Subject: [PATCH 219/814] block: Add no_coroutine_fn and coroutine_mixed_fn marker Add more annotations to functions, describing valid and invalid calls from coroutine to non-coroutine context. When applied to a function, no_coroutine_fn advertises that it should not be called from coroutine_fn functions. This can be because the function blocks or, in the case of generated_co_wrapper, to enforce that coroutine_fn functions directly call the coroutine_fn that backs the generated_co_wrapper. coroutine_mixed_fn instead is for function that can be called in both coroutine and non-coroutine context, but will suspend when called in coroutine context. Annotating them is a first step towards enforcing that non-annotated functions are absolutely not going to suspend. These can be used for example with the vrc tool: # find functions that *really* cannot be called from no_coroutine_fn (vrc) load --loader clang libblock.fa.p/meson-generated_.._block_block-gen.c.o (vrc) paths [no_coroutine_fn,!coroutine_mixed_fn] bdrv_remove_persistent_dirty_bitmap bdrv_create bdrv_can_store_new_dirty_bitmap # find how coroutine_fns end up calling a mixed function (vrc) load --loader clang --force libblock.fa.p/*.c.o (vrc) paths [coroutine_fn] [!no_coroutine_fn]* [coroutine_mixed_fn] ... bdrv_pread <- vhdx_log_write <- vhdx_log_write_and_flush <- vhdx_co_writev ... Signed-off-by: Alberto Faria [Rebase, add coroutine_mixed_fn. - Paolo] Signed-off-by: Paolo Bonzini Message-Id: <20221216110758.559947-3-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/block/block-common.h | 11 ++++++---- include/qemu/osdep.h | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/include/block/block-common.h b/include/block/block-common.h index 41686810de..469300fe8d 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -45,11 +45,14 @@ * - co_wrapper_mixed_bdrv_rdlock are co_wrapper_mixed functions but * automatically take and release the graph rdlock when creating a new * coroutine. + * + * These functions should not be called from a coroutine_fn; instead, + * call the wrapped function directly. */ -#define co_wrapper -#define co_wrapper_mixed -#define co_wrapper_bdrv_rdlock -#define co_wrapper_mixed_bdrv_rdlock +#define co_wrapper no_coroutine_fn +#define co_wrapper_mixed no_coroutine_fn coroutine_mixed_fn +#define co_wrapper_bdrv_rdlock no_coroutine_fn +#define co_wrapper_mixed_bdrv_rdlock no_coroutine_fn coroutine_mixed_fn #include "block/blockjob.h" diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index d1be7bf8b9..88c9facbf2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -177,6 +177,46 @@ extern "C" { #define coroutine_fn #endif +/** + * Mark a function that can suspend when executed in coroutine context, + * but can handle running in non-coroutine context too. + */ +#ifdef __clang__ +#define coroutine_mixed_fn __attribute__((__annotate__("coroutine_mixed_fn"))) +#else +#define coroutine_mixed_fn +#endif + +/** + * Mark a function that should not be called from a coroutine context. + * Usually there will be an analogous, coroutine_fn function that should + * be used instead. + * + * When the function is also marked as coroutine_mixed_fn, the function should + * only be called if the caller does not know whether it is in coroutine + * context. + * + * Functions that are only no_coroutine_fn, on the other hand, should not + * be called from within coroutines at all. This for example includes + * functions that block. + * + * In the future it would be nice to enable compiler or static checker + * support for catching such errors. This annotation is the first step + * towards this, and in the meantime it serves as documentation. + * + * For example: + * + * static void no_coroutine_fn foo(void) { + * .... + * } + */ +#ifdef __clang__ +#define no_coroutine_fn __attribute__((__annotate__("no_coroutine_fn"))) +#else +#define no_coroutine_fn +#endif + + /* * For mingw, as of v6.0.0, the function implementing the assert macro is * not marked as noreturn, so the compiler cannot delete code following an From 264dcbb2b1e5b66d7a5b08662b200c2b315dce0f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 15 Dec 2022 14:02:23 +0100 Subject: [PATCH 220/814] qemu-io: do not reinvent the blk_pwrite_zeroes wheel qemu-io's do_co_pwrite_zeroes is reinventing the coroutine wrapper blk_pwrite_zeroes. Just use the real thing directly. Signed-off-by: Paolo Bonzini Message-Id: <20221215130225.476477-1-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- qemu-io-cmds.c | 55 +++++++++----------------------------------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 952dc940f1..7a412d6512 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -572,54 +572,17 @@ static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, return 1; } -typedef struct { - BlockBackend *blk; - int64_t offset; - int64_t bytes; - int64_t *total; - int flags; - int ret; - bool done; -} CoWriteZeroes; - -static void coroutine_fn co_pwrite_zeroes_entry(void *opaque) -{ - CoWriteZeroes *data = opaque; - - data->ret = blk_co_pwrite_zeroes(data->blk, data->offset, data->bytes, - data->flags); - data->done = true; - if (data->ret < 0) { - *data->total = data->ret; - return; - } - - *data->total = data->bytes; -} - -static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, +static int do_pwrite_zeroes(BlockBackend *blk, int64_t offset, int64_t bytes, int flags, int64_t *total) { - Coroutine *co; - CoWriteZeroes data = { - .blk = blk, - .offset = offset, - .bytes = bytes, - .total = total, - .flags = flags, - .done = false, - }; + int ret = blk_pwrite_zeroes(blk, offset, bytes, + flags | BDRV_REQ_ZERO_WRITE); - co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data); - bdrv_coroutine_enter(blk_bs(blk), co); - while (!data.done) { - aio_poll(blk_get_aio_context(blk), true); - } - if (data.ret < 0) { - return data.ret; - } else { - return 1; + if (ret < 0) { + return ret; } + *total = bytes; + return 1; } static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, @@ -1042,7 +1005,7 @@ static void write_help(void) " -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" " -u, -- with -z, allow unmapping\n" -" -z, -- write zeroes using blk_co_pwrite_zeroes\n" +" -z, -- write zeroes using blk_pwrite_zeroes\n" "\n"); } @@ -1199,7 +1162,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) if (bflag) { ret = do_save_vmstate(blk, buf, offset, count, &total); } else if (zflag) { - ret = do_co_pwrite_zeroes(blk, offset, count, flags, &total); + ret = do_pwrite_zeroes(blk, offset, count, flags, &total); } else if (cflag) { ret = do_write_compressed(blk, buf, offset, count, &total); } else { From 3d65110f0cd453ac5a5a9c4211902271775eba75 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 15 Dec 2022 14:02:24 +0100 Subject: [PATCH 221/814] block: remove bdrv_coroutine_enter It has only one caller---inline it and remove the function. Signed-off-by: Paolo Bonzini Message-Id: <20221215130225.476477-2-pbonzini@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block.c | 6 ------ block/block-backend.c | 2 +- include/block/block-io.h | 5 ----- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/block.c b/block.c index b4a89207ad..ad92fdf1b3 100644 --- a/block.c +++ b/block.c @@ -7178,12 +7178,6 @@ void coroutine_fn bdrv_co_unlock(BlockDriverState *bs) } } -void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) -{ - IO_CODE(); - aio_co_enter(bdrv_get_aio_context(bs), co); -} - static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban) { GLOBAL_STATE_CODE(); diff --git a/block/block-backend.c b/block/block-backend.c index ba7bf1d6bc..8fbb787f41 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1555,7 +1555,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, acb->has_returned = false; co = qemu_coroutine_create(co_entry, acb); - bdrv_coroutine_enter(blk_bs(blk), co); + aio_co_enter(blk_get_aio_context(blk), co); acb->has_returned = true; if (acb->rwco.ret != NOT_DONE) { diff --git a/include/block/block-io.h b/include/block/block-io.h index 3398351596..8d571ec2fb 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -213,11 +213,6 @@ AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs); */ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); -/** - * Transfer control to @co in the aio context of @bs - */ -void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co); - AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); void bdrv_io_plug(BlockDriverState *bs); From b03dd9613bcf8fe948581b2b3585510cb525c382 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 12 Jan 2023 20:14:51 +0100 Subject: [PATCH 222/814] qcow2: Fix theoretical corruption in store_bitmap() error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to write the bitmap table to the image file, it is converted to big endian. If the write fails, it is passed to clear_bitmap_table() to free all of the clusters it had allocated before. However, if we don't convert it back to native endianness first, we'll free things at a wrong offset. In practical terms, the offsets will be so high that we won't actually free any allocated clusters, but just run into an error, but in theory this can cause image corruption. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Message-Id: <20230112191454.169353-2-kwolf@redhat.com> Reviewed-by: Hanna Czenczek Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- block/qcow2-bitmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 385260a1b5..5f456a2785 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -117,7 +117,7 @@ static int update_header_sync(BlockDriverState *bs) return bdrv_flush(bs->file->bs); } -static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size) +static inline void bitmap_table_bswap_be(uint64_t *bitmap_table, size_t size) { size_t i; @@ -1403,9 +1403,10 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) goto fail; } - bitmap_table_to_be(tb, tb_size); + bitmap_table_bswap_be(tb, tb_size); ret = bdrv_pwrite(bs->file, tb_offset, tb_size * sizeof(tb[0]), tb, 0); if (ret < 0) { + bitmap_table_bswap_be(tb, tb_size); error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", bm_name); goto fail; From 44efba2d713aca076c411594d0c1a2b99155eeb3 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 12 Jan 2023 20:14:52 +0100 Subject: [PATCH 223/814] qemu-img commit: Report errors while closing the image blk_unref() can't report any errors that happen while closing the image. For example, if qcow2 hits an -ENOSPC error while writing out dirty bitmaps when it's closed, it prints error messages to stderr, but 'qemu-img commit' won't see any error return value and will therefore look successful with exit code 0. In order to fix this, manually inactivate the image first before calling blk_unref(). This already performs the operations that would be most likely to fail while closing the image, but it can still return errors. Signed-off-by: Kevin Wolf Message-Id: <20230112191454.169353-3-kwolf@redhat.com> Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- qemu-img.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/qemu-img.c b/qemu-img.c index 7e73c5c1da..7b9ba99f5d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -450,6 +450,11 @@ static BlockBackend *img_open(bool image_opts, blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet, force_share); } + + if (blk) { + blk_set_force_allow_inactivate(blk); + } + return blk; } @@ -1120,6 +1125,14 @@ unref_backing: done: qemu_progress_end(); + /* + * Manually inactivate the image first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + ret = bdrv_inactivate_all(); + if (ret < 0 && !local_err) { + error_setg_errno(&local_err, -ret, "Error while closing the image"); + } blk_unref(blk); if (local_err) { From c5e477110dcb8ef4642dce399777c3dee68fa96c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 12 Jan 2023 20:14:53 +0100 Subject: [PATCH 224/814] qemu-img bitmap: Report errors while closing the image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit blk_unref() can't report any errors that happen while closing the image. For example, if qcow2 hits an -ENOSPC error while writing out dirty bitmaps when it's closed, it prints error messages to stderr, but 'qemu-img bitmap' won't see any error return value and will therefore look successful with exit code 0. In order to fix this, manually inactivate the image first before calling blk_unref(). This already performs the operations that would be most likely to fail while closing the image, but it can still return errors. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1330 Signed-off-by: Kevin Wolf Message-Id: <20230112191454.169353-4-kwolf@redhat.com> Reviewed-by: Hanna Czenczek Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- qemu-img.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/qemu-img.c b/qemu-img.c index 7b9ba99f5d..5bb63c5e0c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4646,6 +4646,7 @@ static int img_bitmap(int argc, char **argv) QSIMPLEQ_HEAD(, ImgBitmapAction) actions; ImgBitmapAction *act, *act_next; const char *op; + int inactivate_ret; QSIMPLEQ_INIT(&actions); @@ -4830,6 +4831,16 @@ static int img_bitmap(int argc, char **argv) ret = 0; out: + /* + * Manually inactivate the images first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + inactivate_ret = bdrv_inactivate_all(); + if (inactivate_ret < 0) { + error_report("Error while closing the image: %s", strerror(-inactivate_ret)); + ret = 1; + } + blk_unref(src); blk_unref(blk); qemu_opts_del(opts); From af76484e54f6c5e20452c2b329378026b8f2c59d Mon Sep 17 00:00:00 2001 From: Dongdong Zhang Date: Wed, 30 Nov 2022 09:53:58 +0800 Subject: [PATCH 225/814] Fix some typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix some typos in 'python' directory. Signed-off-by: Dongdong Zhang Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221130015358.6998-2-zhangdongdong@eswincomputing.com [Fixed additional typo spotted by Max Filippov. --js] Reviewed-by: John Snow Signed-off-by: John Snow --- python/qemu/machine/console_socket.py | 2 +- python/qemu/machine/qtest.py | 2 +- python/qemu/qmp/protocol.py | 2 +- python/qemu/qmp/qmp_tui.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/qemu/machine/console_socket.py b/python/qemu/machine/console_socket.py index 8c4ff598ad..4e28ba9bb2 100644 --- a/python/qemu/machine/console_socket.py +++ b/python/qemu/machine/console_socket.py @@ -68,7 +68,7 @@ class ConsoleSocket(socket.socket): """Kick off a thread to drain the socket.""" # Configure socket to not block and timeout. # This allows our drain thread to not block - # on recieve and exit smoothly. + # on receive and exit smoothly. socket.socket.setblocking(self, False) socket.socket.settimeout(self, 1) drain_thread = threading.Thread(target=self._drain_fn) diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py index 1a1fc6c9b0..1c46138bd0 100644 --- a/python/qemu/machine/qtest.py +++ b/python/qemu/machine/qtest.py @@ -42,7 +42,7 @@ class QEMUQtestProtocol: :raise socket.error: on socket connection errors .. note:: - No conection is estabalished by __init__(), this is done + No connection is established by __init__(), this is done by the connect() or accept() methods. """ def __init__(self, address: SocketAddrT, diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py index 6ea86650ad..15909b7dba 100644 --- a/python/qemu/qmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -812,7 +812,7 @@ class AsyncProtocol(Generic[T]): @bottom_half async def _bh_close_stream(self, error_pathway: bool = False) -> None: - # NB: Closing the writer also implcitly closes the reader. + # NB: Closing the writer also implicitly closes the reader. if not self._writer: return diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py index ce239d8979..8369144723 100644 --- a/python/qemu/qmp/qmp_tui.py +++ b/python/qemu/qmp/qmp_tui.py @@ -71,7 +71,7 @@ def format_json(msg: str) -> str: due to an decoding error then a simple string manipulation is done to achieve a single line JSON string. - Converting into single line is more asthetically pleasing when looking + Converting into single line is more aesthetically pleasing when looking along with error messages. Eg: @@ -91,7 +91,7 @@ def format_json(msg: str) -> str: [1, true, 3]: QMP message is not a JSON object. - The single line mode is more asthetically pleasing. + The single line mode is more aesthetically pleasing. :param msg: The message to formatted into single line. @@ -498,7 +498,7 @@ class EditorWidget(urwid.Filler): class HistoryBox(urwid.ListBox): """ This widget is modelled using the ListBox widget, contains the list of - all messages both QMP messages and log messsages to be shown in the TUI. + all messages both QMP messages and log messages to be shown in the TUI. The messages are urwid.Text widgets. On every append of a message, the focus is shifted to the last appended message. From ada73a492cb29b9c3a9f88c5e6d3407fa0d999e7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 24 Jun 2022 22:52:52 +0300 Subject: [PATCH 226/814] python: QEMUMachine: enable qmp accept timeout by default I've spent much time trying to debug hanging pipeline in gitlab. I started from and idea that I have problem in code in my series (which has some timeouts). Finally I found that the problem is that I've used QEMUMachine class directly to avoid qtest, and didn't add necessary arguments. Qemu fails and we wait for qmp accept endlessly. In gitlab it's just stopped by timeout (one hour) with no sign of what's going wrong. With timeout enabled, gitlab don't wait for an hour and prints all needed information. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Message-Id: <20220624195252.175249-1-vsementsov@yandex-team.ru> [Fixed typing. --js] Signed-off-by: John Snow --- python/qemu/machine/machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 748a0d807c..c759db03e4 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -131,7 +131,7 @@ class QEMUMachine: drain_console: bool = False, console_log: Optional[str] = None, log_dir: Optional[str] = None, - qmp_timer: Optional[float] = None): + qmp_timer: Optional[float] = 30): ''' Initialize a QEMUMachine From f9922937d173f50fe59fd1b20fadc445fb6b2564 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 10 Jan 2023 00:29:30 -0800 Subject: [PATCH 227/814] python/machine: Fix AF_UNIX path too long on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS, private $TMPDIR's are the default. These $TMPDIR's are generated from a user's unix UID and UUID [1], which can create a relatively long path: /var/folders/d7/rz20f6hd709c1ty8f6_6y_z40000gn/T/ QEMU's avocado tests create a temporary directory prefixed by "avo_qemu_sock_", and create QMP sockets within _that_ as well. The QMP socket is unnecessarily long, because a temporary directory is created for every QEMUMachine object. /avo_qemu_sock_uh3w_dgc/qemu-37331-10bacf110-monitor.sock The path limit for unix sockets on macOS is 104: [2] /* * [XSI] Definitions for UNIX IPC domain. */ struct sockaddr_un { unsigned char sun_len; /* sockaddr len including null */ sa_family_t sun_family; /* [XSI] AF_UNIX */ char sun_path[104]; /* [XSI] path name (gag) */ }; This results in avocado tests failing on macOS because the QMP unix socket can't be created, because the path is too long: ERROR| Failed to establish connection: OSError: AF_UNIX path too long This change resolves by reducing the size of the socket directory prefix and the suffix on the QMP and console socket names. The result is paths like this: pdel@pdel-mbp:/var/folders/d7/rz20f6hd709c1ty8f6_6y_z40000gn/T $ tree qemu* qemu_df4evjeq qemu_jbxel3gy qemu_ml9s_gg7 qemu_oc7h7f3u qemu_oqb1yf97 ├── 10a004050.con └── 10a004050.qmp [1] https://apple.stackexchange.com/questions/353832/why-is-mac-osx-temp-directory-in-weird-path [2] /Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/usr/include/sys/un.h Signed-off-by: Peter Delevoryas Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230110082930.42129-2-peter@pjd.dev Signed-off-by: John Snow --- python/qemu/machine/machine.py | 6 +++--- tests/avocado/avocado_qemu/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index c759db03e4..a71d87ead4 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -157,7 +157,7 @@ class QEMUMachine: self._wrapper = wrapper self._qmp_timer = qmp_timer - self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" + self._name = name or f"{id(self):x}" self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir @@ -167,7 +167,7 @@ class QEMUMachine: self._monitor_address = monitor_address else: self._monitor_address = os.path.join( - self.sock_dir, f"{self._name}-monitor.sock" + self.sock_dir, f"{self._name}.qmp" ) self._console_log_path = console_log @@ -192,7 +192,7 @@ class QEMUMachine: self._console_set = False self._console_device_type: Optional[str] = None self._console_address = os.path.join( - self.sock_dir, f"{self._name}-console.sock" + self.sock_dir, f"{self._name}.con" ) self._console_socket: Optional[socket.socket] = None self._remove_files: List[str] = [] diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 910f3ba1ea..25a546842f 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -306,7 +306,7 @@ class QemuSystemTest(QemuBaseTest): self.cancel('no support for user networking') def _new_vm(self, name, *args): - self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") + self._sd = tempfile.TemporaryDirectory(prefix="qemu_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, sock_dir=self._sd.name, log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) From 166464c6ce82f748e33b24361a72e9d310130fa0 Mon Sep 17 00:00:00 2001 From: Maksim Davydov Date: Thu, 12 Jan 2023 18:28:03 +0300 Subject: [PATCH 228/814] python/qmp: increase read buffer size Current 256KB is not enough for some real cases. As a possible solution limit can be chosen to be the same as libvirt (10MB) Signed-off-by: Maksim Davydov Reviewed-by: John Snow Message-id: 20230112152805.33109-3-davydov-max@yandex-team.ru Signed-off-by: John Snow --- python/qemu/qmp/qmp_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/qemu/qmp/qmp_client.py b/python/qemu/qmp/qmp_client.py index 5dcda04a75..b5772e7f32 100644 --- a/python/qemu/qmp/qmp_client.py +++ b/python/qemu/qmp/qmp_client.py @@ -197,8 +197,8 @@ class QMPClient(AsyncProtocol[Message], Events): #: Logger object used for debugging messages. logger = logging.getLogger(__name__) - # Read buffer limit; large enough to accept query-qmp-schema - _limit = (256 * 1024) + # Read buffer limit; 10MB like libvirt default + _limit = (10 * 1024 * 1024) # Type alias for pending execute() result items _PendingT = Union[Message, ExecInterruptedError] From a3cfea92e2030926e00a2519d299384ea648e36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 11 Jan 2023 12:00:59 +0400 Subject: [PATCH 229/814] python/qmp/protocol: add open_with_socket() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of listening for incoming connections with a SocketAddr, add a new method open_with_socket() that accepts an existing socket. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-id: 20230111080101.969151-2-marcandre.lureau@redhat.com Signed-off-by: John Snow --- python/qemu/qmp/protocol.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py index 15909b7dba..6d3d739daa 100644 --- a/python/qemu/qmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -18,6 +18,7 @@ from asyncio import StreamReader, StreamWriter from enum import Enum from functools import wraps import logging +import socket from ssl import SSLContext from typing import ( Any, @@ -296,6 +297,19 @@ class AsyncProtocol(Generic[T]): await self.accept() assert self.runstate == Runstate.RUNNING + @upper_half + @require(Runstate.IDLE) + async def open_with_socket(self, sock: socket.socket) -> None: + """ + Start connection with given socket. + + :param sock: A socket. + + :raise StateError: When the `Runstate` is not `IDLE`. + """ + self._reader, self._writer = await asyncio.open_connection(sock=sock) + self._set_state(Runstate.CONNECTING) + @upper_half @require(Runstate.IDLE) async def start_server(self, address: SocketAddrT, @@ -343,11 +357,12 @@ class AsyncProtocol(Generic[T]): protocol-level failure occurs while establishing a new session, the wrapped error may also be an `QMPError`. """ - if self._accepted is None: - raise QMPError("Cannot call accept() before start_server().") - await self._session_guard( - self._do_accept(), - 'Failed to establish connection') + if not self._reader: + if self._accepted is None: + raise QMPError("Cannot call accept() before start_server().") + await self._session_guard( + self._do_accept(), + 'Failed to establish connection') await self._session_guard( self._establish_session(), 'Failed to establish session') From 603a3bad4b9a95b524dc8d6a41b1be4d5c5cacdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 11 Jan 2023 12:01:00 +0400 Subject: [PATCH 230/814] python/qmp/legacy: make QEMUMonitorProtocol accept a socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Teach QEMUMonitorProtocol to accept an exisiting socket. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-id: 20230111080101.969151-3-marcandre.lureau@redhat.com Signed-off-by: John Snow --- python/qemu/qmp/legacy.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index 1951754455..8b09ee7dbb 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -22,6 +22,7 @@ old interface. # import asyncio +import socket from types import TracebackType from typing import ( Any, @@ -69,22 +70,32 @@ class QEMUMonitorProtocol: :param address: QEMU address, can be either a unix socket path (string) or a tuple in the form ( address, port ) for a TCP - connection + connection or None + :param sock: a socket or None :param server: Act as the socket server. (See 'accept') :param nickname: Optional nickname used for logging. """ - def __init__(self, address: SocketAddrT, + def __init__(self, + address: Optional[SocketAddrT] = None, + sock: Optional[socket.socket] = None, server: bool = False, nickname: Optional[str] = None): + assert address or sock self._qmp = QMPClient(nickname) self._aloop = asyncio.get_event_loop() self._address = address + self._sock = sock self._timeout: Optional[float] = None if server: - self._sync(self._qmp.start_server(self._address)) + if sock: + assert self._sock is not None + self._sync(self._qmp.open_with_socket(self._sock)) + else: + assert self._address is not None + self._sync(self._qmp.start_server(self._address)) _T = TypeVar('_T') @@ -139,6 +150,7 @@ class QEMUMonitorProtocol: :return: QMP greeting dict, or None if negotiate is false :raise ConnectError: on connection errors """ + assert self._address is not None self._qmp.await_greeting = negotiate self._qmp.negotiate = negotiate From bd4c0ef409140bd1be393407c04005ac077d4574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 11 Jan 2023 12:01:01 +0400 Subject: [PATCH 231/814] python/qemu/machine: use socketpair() for QMP by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no monitor address is given, establish the QMP communication through a socketpair() (API is also supported on Windows since Python 3.5) Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-id: 20230111080101.969151-4-marcandre.lureau@redhat.com [Resolved conflicts, fixed typing error. --js] Signed-off-by: John Snow --- python/qemu/machine/machine.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index a71d87ead4..e57c254484 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -158,17 +158,13 @@ class QEMUMachine: self._qmp_timer = qmp_timer self._name = name or f"{id(self):x}" + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir self._log_dir = log_dir - if monitor_address is not None: - self._monitor_address = monitor_address - else: - self._monitor_address = os.path.join( - self.sock_dir, f"{self._name}.qmp" - ) + self._monitor_address = monitor_address self._console_log_path = console_log if self._console_log_path: @@ -303,7 +299,11 @@ class QEMUMachine: args = ['-display', 'none', '-vga', 'none'] if self._qmp_set: - if isinstance(self._monitor_address, tuple): + if self._sock_pair: + fd = self._sock_pair[0].fileno() + os.set_inheritable(fd, True) + moncdev = f"socket,id=mon,fd={fd}" + elif isinstance(self._monitor_address, tuple): moncdev = "socket,id=mon,host={},port={}".format( *self._monitor_address ) @@ -337,10 +337,17 @@ class QEMUMachine: self._remove_files.append(self._console_address) if self._qmp_set: + monitor_address = None + sock = None + if self._monitor_address is None: + self._sock_pair = socket.socketpair() + sock = self._sock_pair[1] if isinstance(self._monitor_address, str): self._remove_files.append(self._monitor_address) + monitor_address = self._monitor_address self._qmp_connection = QEMUMonitorProtocol( - self._monitor_address, + address=monitor_address, + sock=sock, server=True, nickname=self._name ) @@ -360,6 +367,8 @@ class QEMUMachine: )) def _post_launch(self) -> None: + if self._sock_pair: + self._sock_pair[0].close() if self._qmp_connection: self._qmp.accept(self._qmp_timer) From ba0fef0dd91dca2db6d1187c47b5d52592f4bee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Nov 2022 18:36:28 +0100 Subject: [PATCH 232/814] linux-user/strace: Constify struct flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit print_flags() takes a const pointer. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20221104173632.1052-2-philmd@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 9ae5a812cd..25c47f0316 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -945,7 +945,7 @@ print_syscall_ret_ioctl(CPUArchState *cpu_env, const struct syscallname *name, } #endif -UNUSED static struct flags access_flags[] = { +UNUSED static const struct flags access_flags[] = { FLAG_GENERIC(F_OK), FLAG_GENERIC(R_OK), FLAG_GENERIC(W_OK), @@ -953,7 +953,7 @@ UNUSED static struct flags access_flags[] = { FLAG_END, }; -UNUSED static struct flags at_file_flags[] = { +UNUSED static const struct flags at_file_flags[] = { #ifdef AT_EACCESS FLAG_GENERIC(AT_EACCESS), #endif @@ -963,14 +963,14 @@ UNUSED static struct flags at_file_flags[] = { FLAG_END, }; -UNUSED static struct flags unlinkat_flags[] = { +UNUSED static const struct flags unlinkat_flags[] = { #ifdef AT_REMOVEDIR FLAG_GENERIC(AT_REMOVEDIR), #endif FLAG_END, }; -UNUSED static struct flags mode_flags[] = { +UNUSED static const struct flags mode_flags[] = { FLAG_GENERIC(S_IFSOCK), FLAG_GENERIC(S_IFLNK), FLAG_GENERIC(S_IFREG), @@ -981,14 +981,14 @@ UNUSED static struct flags mode_flags[] = { FLAG_END, }; -UNUSED static struct flags open_access_flags[] = { +UNUSED static const struct flags open_access_flags[] = { FLAG_TARGET(O_RDONLY), FLAG_TARGET(O_WRONLY), FLAG_TARGET(O_RDWR), FLAG_END, }; -UNUSED static struct flags open_flags[] = { +UNUSED static const struct flags open_flags[] = { FLAG_TARGET(O_APPEND), FLAG_TARGET(O_CREAT), FLAG_TARGET(O_DIRECTORY), @@ -1019,7 +1019,7 @@ UNUSED static struct flags open_flags[] = { FLAG_END, }; -UNUSED static struct flags mount_flags[] = { +UNUSED static const struct flags mount_flags[] = { #ifdef MS_BIND FLAG_GENERIC(MS_BIND), #endif @@ -1044,7 +1044,7 @@ UNUSED static struct flags mount_flags[] = { FLAG_END, }; -UNUSED static struct flags umount2_flags[] = { +UNUSED static const struct flags umount2_flags[] = { #ifdef MNT_FORCE FLAG_GENERIC(MNT_FORCE), #endif @@ -1057,7 +1057,7 @@ UNUSED static struct flags umount2_flags[] = { FLAG_END, }; -UNUSED static struct flags mmap_prot_flags[] = { +UNUSED static const struct flags mmap_prot_flags[] = { FLAG_GENERIC(PROT_NONE), FLAG_GENERIC(PROT_EXEC), FLAG_GENERIC(PROT_READ), @@ -1068,7 +1068,7 @@ UNUSED static struct flags mmap_prot_flags[] = { FLAG_END, }; -UNUSED static struct flags mmap_flags[] = { +UNUSED static const struct flags mmap_flags[] = { FLAG_TARGET(MAP_SHARED), FLAG_TARGET(MAP_PRIVATE), FLAG_TARGET(MAP_ANONYMOUS), @@ -1092,7 +1092,7 @@ UNUSED static struct flags mmap_flags[] = { FLAG_END, }; -UNUSED static struct flags clone_flags[] = { +UNUSED static const struct flags clone_flags[] = { FLAG_GENERIC(CLONE_VM), FLAG_GENERIC(CLONE_FS), FLAG_GENERIC(CLONE_FILES), @@ -1136,7 +1136,7 @@ UNUSED static struct flags clone_flags[] = { FLAG_END, }; -UNUSED static struct flags msg_flags[] = { +UNUSED static const struct flags msg_flags[] = { /* send */ FLAG_GENERIC(MSG_CONFIRM), FLAG_GENERIC(MSG_DONTROUTE), @@ -1156,7 +1156,7 @@ UNUSED static struct flags msg_flags[] = { FLAG_END, }; -UNUSED static struct flags statx_flags[] = { +UNUSED static const struct flags statx_flags[] = { #ifdef AT_EMPTY_PATH FLAG_GENERIC(AT_EMPTY_PATH), #endif @@ -1178,7 +1178,7 @@ UNUSED static struct flags statx_flags[] = { FLAG_END, }; -UNUSED static struct flags statx_mask[] = { +UNUSED static const struct flags statx_mask[] = { /* This must come first, because it includes everything. */ #ifdef STATX_ALL FLAG_GENERIC(STATX_ALL), @@ -1226,7 +1226,7 @@ UNUSED static struct flags statx_mask[] = { FLAG_END, }; -UNUSED static struct flags falloc_flags[] = { +UNUSED static const struct flags falloc_flags[] = { FLAG_GENERIC(FALLOC_FL_KEEP_SIZE), FLAG_GENERIC(FALLOC_FL_PUNCH_HOLE), #ifdef FALLOC_FL_NO_HIDE_STALE @@ -1246,7 +1246,7 @@ UNUSED static struct flags falloc_flags[] = { #endif }; -UNUSED static struct flags termios_iflags[] = { +UNUSED static const struct flags termios_iflags[] = { FLAG_TARGET(IGNBRK), FLAG_TARGET(BRKINT), FLAG_TARGET(IGNPAR), @@ -1265,7 +1265,7 @@ UNUSED static struct flags termios_iflags[] = { FLAG_END, }; -UNUSED static struct flags termios_oflags[] = { +UNUSED static const struct flags termios_oflags[] = { FLAG_TARGET(OPOST), FLAG_TARGET(OLCUC), FLAG_TARGET(ONLCR), @@ -1349,7 +1349,7 @@ UNUSED static struct enums termios_cflags_CSIZE[] = { ENUM_END, }; -UNUSED static struct flags termios_cflags[] = { +UNUSED static const struct flags termios_cflags[] = { FLAG_TARGET(CSTOPB), FLAG_TARGET(CREAD), FLAG_TARGET(PARENB), @@ -1360,7 +1360,7 @@ UNUSED static struct flags termios_cflags[] = { FLAG_END, }; -UNUSED static struct flags termios_lflags[] = { +UNUSED static const struct flags termios_lflags[] = { FLAG_TARGET(ISIG), FLAG_TARGET(ICANON), FLAG_TARGET(XCASE), @@ -1380,7 +1380,7 @@ UNUSED static struct flags termios_lflags[] = { FLAG_END, }; -UNUSED static struct flags mlockall_flags[] = { +UNUSED static const struct flags mlockall_flags[] = { FLAG_TARGET(MCL_CURRENT), FLAG_TARGET(MCL_FUTURE), #ifdef MCL_ONFAULT From 24acb7b4743ff6e9454e8407668b77d432cf23f7 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 4 Nov 2022 18:36:29 +0100 Subject: [PATCH 233/814] linux-user/strace: Extract print_execve_argv() from print_execve() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to add print_execveat() which re-use common code from print_execve(), extract print_execve_argv() from it. Signed-off-by: Drew DeVault Message-Id: <20221104081015.706009-1-sir@cmpwn.com> [PMD: Split of bigger patch, filled description, fixed style] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20221104173632.1052-3-philmd@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 71 +++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 25c47f0316..3d11d2f759 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -616,38 +616,6 @@ print_semctl(CPUArchState *cpu_env, const struct syscallname *name, } #endif -static void -print_execve(CPUArchState *cpu_env, const struct syscallname *name, - abi_long arg1, abi_long arg2, abi_long arg3, - abi_long arg4, abi_long arg5, abi_long arg6) -{ - abi_ulong arg_ptr_addr; - char *s; - - if (!(s = lock_user_string(arg1))) - return; - qemu_log("%s(\"%s\",{", name->name, s); - unlock_user(s, arg1, 0); - - for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { - abi_ulong *arg_ptr, arg_addr; - - arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); - if (!arg_ptr) - return; - arg_addr = tswapal(*arg_ptr); - unlock_user(arg_ptr, arg_ptr_addr, 0); - if (!arg_addr) - break; - if ((s = lock_user_string(arg_addr))) { - qemu_log("\"%s\",", s); - unlock_user(s, arg_addr, 0); - } - } - - qemu_log("NULL})"); -} - #ifdef TARGET_NR_ipc static void print_ipc(CPUArchState *cpu_env, const struct syscallname *name, @@ -1969,6 +1937,45 @@ print_execv(CPUArchState *cpu_env, const struct syscallname *name, } #endif +static void +print_execve_argv(abi_long argv, int last) +{ + abi_ulong arg_ptr_addr; + char *s; + + qemu_log("{"); + for (arg_ptr_addr = argv; ; arg_ptr_addr += sizeof(abi_ulong)) { + abi_ulong *arg_ptr, arg_addr; + + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); + if (!arg_ptr) { + return; + } + arg_addr = tswapal(*arg_ptr); + unlock_user(arg_ptr, arg_ptr_addr, 0); + if (!arg_addr) { + break; + } + s = lock_user_string(arg_addr); + if (s) { + qemu_log("\"%s\",", s); + unlock_user(s, arg_addr, 0); + } + } + qemu_log("NULL}%s", get_comma(last)); +} + +static void +print_execve(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + print_syscall_prologue(name); + print_string(arg1, 0); + print_execve_argv(arg2, 1); + print_syscall_epilogue(name); +} + #if defined(TARGET_NR_faccessat) || defined(TARGET_NR_faccessat2) static void print_faccessat(CPUArchState *cpu_env, const struct syscallname *name, From 5667a1aebe93e2bb2ca435f1eef2f1e187b005bf Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 4 Nov 2022 18:36:30 +0100 Subject: [PATCH 234/814] linux-user/strace: Add output for execveat() syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Drew DeVault Message-Id: <20221104081015.706009-1-sir@cmpwn.com> Suggested-by: Helge Deller [PMD: Split of bigger patch] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20221104173632.1052-4-philmd@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 23 +++++++++++++++++++++++ linux-user/strace.list | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 3d11d2f759..7bccb4f0c0 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1104,6 +1104,16 @@ UNUSED static const struct flags clone_flags[] = { FLAG_END, }; +UNUSED static const struct flags execveat_flags[] = { +#ifdef AT_EMPTY_PATH + FLAG_GENERIC(AT_EMPTY_PATH), +#endif +#ifdef AT_SYMLINK_NOFOLLOW + FLAG_GENERIC(AT_SYMLINK_NOFOLLOW), +#endif + FLAG_END, +}; + UNUSED static const struct flags msg_flags[] = { /* send */ FLAG_GENERIC(MSG_CONFIRM), @@ -1976,6 +1986,19 @@ print_execve(CPUArchState *cpu_env, const struct syscallname *name, print_syscall_epilogue(name); } +static void +print_execveat(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +{ + print_syscall_prologue(name); + print_at_dirfd(arg1, 0); + print_string(arg2, 0); + print_execve_argv(arg3, 0); + print_flags(execveat_flags, arg5, 1); + print_syscall_epilogue(name); +} + #if defined(TARGET_NR_faccessat) || defined(TARGET_NR_faccessat2) static void print_faccessat(CPUArchState *cpu_env, const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index 3a898e2532..bb21c05414 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -164,7 +164,7 @@ { TARGET_NR_execve, "execve" , NULL, print_execve, NULL }, #endif #ifdef TARGET_NR_execveat -{ TARGET_NR_execveat, "execveat" , NULL, NULL, NULL }, +{ TARGET_NR_execveat, "execveat" , NULL, print_execveat, NULL }, #endif #ifdef TARGET_NR_exec_with_loader { TARGET_NR_exec_with_loader, "exec_with_loader" , NULL, NULL, NULL }, From 156e1f67182f61cce113ab5e69e3a73af43ba2cb Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 4 Nov 2022 18:36:31 +0100 Subject: [PATCH 235/814] linux-user/syscall: Extract do_execve() from do_syscall1() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit execve() is a particular case of execveat(). In order to add do_execveat(), first factor do_execve() out. Signed-off-by: Drew DeVault Message-Id: <20221104081015.706009-1-sir@cmpwn.com> [PMD: Split of bigger patch, filled description, fixed style] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20221104173632.1052-5-philmd@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 211 +++++++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 97 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1f8c10f8ef..11236d16a3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8357,6 +8357,119 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int return safe_openat(dirfd, path(pathname), flags, mode); } +static int do_execve(CPUArchState *cpu_env, + abi_long pathname, abi_long guest_argp, + abi_long guest_envp) +{ + int ret; + char **argp, **envp; + int argc, envc; + abi_ulong gp; + abi_ulong addr; + char **q; + void *p; + + argc = 0; + + for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) { + return -TARGET_EFAULT; + } + if (!addr) { + break; + } + argc++; + } + envc = 0; + for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { + if (get_user_ual(addr, gp)) { + return -TARGET_EFAULT; + } + if (!addr) { + break; + } + envc++; + } + + argp = g_new0(char *, argc + 1); + envp = g_new0(char *, envc + 1); + + for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + goto execve_efault; + } + if (!addr) { + break; + } + *q = lock_user_string(addr); + if (!*q) { + goto execve_efault; + } + } + *q = NULL; + + for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp)) { + goto execve_efault; + } + if (!addr) { + break; + } + *q = lock_user_string(addr); + if (!*q) { + goto execve_efault; + } + } + *q = NULL; + + /* + * Although execve() is not an interruptible syscall it is + * a special case where we must use the safe_syscall wrapper: + * if we allow a signal to happen before we make the host + * syscall then we will 'lose' it, because at the point of + * execve the process leaves QEMU's control. So we use the + * safe syscall wrapper to ensure that we either take the + * signal as a guest signal, or else it does not happen + * before the execve completes and makes it the other + * program's problem. + */ + p = lock_user_string(pathname); + if (!p) { + goto execve_efault; + } + + if (is_proc_myself(p, "exe")) { + ret = get_errno(safe_execve(exec_path, argp, envp)); + } else { + ret = get_errno(safe_execve(p, argp, envp)); + } + + unlock_user(p, pathname, 0); + + goto execve_end; + +execve_efault: + ret = -TARGET_EFAULT; + +execve_end: + for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) { + break; + } + unlock_user(*q, addr, 0); + } + for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { + if (get_user_ual(addr, gp) || !addr) { + break; + } + unlock_user(*q, addr, 0); + } + + g_free(argp); + g_free(envp); + return ret; +} + #define TIMER_MAGIC 0x0caf0000 #define TIMER_MAGIC_MASK 0xffff0000 @@ -8867,103 +8980,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return ret; #endif case TARGET_NR_execve: - { - char **argp, **envp; - int argc, envc; - abi_ulong gp; - abi_ulong guest_argp; - abi_ulong guest_envp; - abi_ulong addr; - char **q; - - argc = 0; - guest_argp = arg2; - for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { - if (get_user_ual(addr, gp)) - return -TARGET_EFAULT; - if (!addr) - break; - argc++; - } - envc = 0; - guest_envp = arg3; - for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { - if (get_user_ual(addr, gp)) - return -TARGET_EFAULT; - if (!addr) - break; - envc++; - } - - argp = g_new0(char *, argc + 1); - envp = g_new0(char *, envc + 1); - - for (gp = guest_argp, q = argp; gp; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp)) - goto execve_efault; - if (!addr) - break; - if (!(*q = lock_user_string(addr))) - goto execve_efault; - } - *q = NULL; - - for (gp = guest_envp, q = envp; gp; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp)) - goto execve_efault; - if (!addr) - break; - if (!(*q = lock_user_string(addr))) - goto execve_efault; - } - *q = NULL; - - if (!(p = lock_user_string(arg1))) - goto execve_efault; - /* Although execve() is not an interruptible syscall it is - * a special case where we must use the safe_syscall wrapper: - * if we allow a signal to happen before we make the host - * syscall then we will 'lose' it, because at the point of - * execve the process leaves QEMU's control. So we use the - * safe syscall wrapper to ensure that we either take the - * signal as a guest signal, or else it does not happen - * before the execve completes and makes it the other - * program's problem. - */ - if (is_proc_myself(p, "exe")) { - ret = get_errno(safe_execve(exec_path, argp, envp)); - } else { - ret = get_errno(safe_execve(p, argp, envp)); - } - unlock_user(p, arg1, 0); - - goto execve_end; - - execve_efault: - ret = -TARGET_EFAULT; - - execve_end: - for (gp = guest_argp, q = argp; *q; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp) - || !addr) - break; - unlock_user(*q, addr, 0); - } - for (gp = guest_envp, q = envp; *q; - gp += sizeof(abi_ulong), q++) { - if (get_user_ual(addr, gp) - || !addr) - break; - unlock_user(*q, addr, 0); - } - - g_free(argp); - g_free(envp); - } - return ret; + return do_execve(cpu_env, arg1, arg2, arg3); case TARGET_NR_chdir: if (!(p = lock_user_string(arg1))) return -TARGET_EFAULT; From 55bbe4d5ee52e77951dda62b08e37cd0dd8ddb5b Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 4 Nov 2022 18:36:32 +0100 Subject: [PATCH 236/814] linux-user/syscall: Implement execveat() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit References: https://gitlab.com/qemu-project/qemu/-/issues/1007 Signed-off-by: Drew DeVault Reviewed-by: Laurent Vivier Message-Id: <20221104081015.706009-1-sir@cmpwn.com> Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221104173632.1052-6-philmd@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 11236d16a3..3e72bd333e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -696,7 +696,8 @@ safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \ #endif safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \ int, options, struct rusage *, rusage) -safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp) +safe_syscall5(int, execveat, int, dirfd, const char *, filename, + char **, argv, char **, envp, int, flags) #if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) || \ defined(TARGET_NR_pselect6) || defined(TARGET_NR_pselect6_time64) safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \ @@ -8357,9 +8358,9 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int return safe_openat(dirfd, path(pathname), flags, mode); } -static int do_execve(CPUArchState *cpu_env, +static int do_execveat(CPUArchState *cpu_env, int dirfd, abi_long pathname, abi_long guest_argp, - abi_long guest_envp) + abi_long guest_envp, int flags) { int ret; char **argp, **envp; @@ -8439,9 +8440,9 @@ static int do_execve(CPUArchState *cpu_env, } if (is_proc_myself(p, "exe")) { - ret = get_errno(safe_execve(exec_path, argp, envp)); + ret = get_errno(safe_execveat(dirfd, exec_path, argp, envp, flags)); } else { - ret = get_errno(safe_execve(p, argp, envp)); + ret = get_errno(safe_execveat(dirfd, p, argp, envp, flags)); } unlock_user(p, pathname, 0); @@ -8979,8 +8980,10 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, unlock_user(p, arg2, 0); return ret; #endif + case TARGET_NR_execveat: + return do_execveat(cpu_env, arg1, arg2, arg3, arg4, arg5); case TARGET_NR_execve: - return do_execve(cpu_env, arg1, arg2, arg3); + return do_execveat(cpu_env, AT_FDCWD, arg1, arg2, arg3, 0); case TARGET_NR_chdir: if (!(p = lock_user_string(arg1))) return -TARGET_EFAULT; From c95031a19f0d7f418a597243f6f84b031a858997 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 18 Jan 2023 13:04:05 +0100 Subject: [PATCH 237/814] tests/qtest: netdev: test stream and dgram backends Signed-off-by: Laurent Vivier Acked-by: Michael S. Tsirkin Message-Id: <20230118120405.1876329-1-lvivier@redhat.com> Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 2 + tests/qtest/netdev-socket.c | 448 ++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 tests/qtest/netdev-socket.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 1af63f8bd2..e97616d327 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -21,6 +21,7 @@ qtests_generic = [ 'test-hmp', 'qos-test', 'readconfig-test', + 'netdev-socket', ] if config_host.has_key('CONFIG_MODULES') qtests_generic += [ 'modules-test' ] @@ -298,6 +299,7 @@ qtests = { 'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), + 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), } gvnc = dependency('gvnc-1.0', required: false) diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c new file mode 100644 index 0000000000..6ba256e173 --- /dev/null +++ b/tests/qtest/netdev-socket.c @@ -0,0 +1,448 @@ +/* + * QTest testcase for netdev stream and dgram + * + * Copyright (c) 2022 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/sockets.h" +#include +#include "../unit/socket-helpers.h" +#include "libqtest.h" + +#define CONNECTION_TIMEOUT 5 + +#define EXPECT_STATE(q, e, t) \ +do { \ + char *resp = NULL; \ + g_test_timer_start(); \ + do { \ + g_free(resp); \ + resp = qtest_hmp(q, "info network"); \ + if (t) { \ + strrchr(resp, t)[0] = 0; \ + } \ + if (g_str_equal(resp, e)) { \ + break; \ + } \ + } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ + g_assert_cmpstr(resp, ==, e); \ + g_free(resp); \ +} while (0) + +static gchar *tmpdir; + +static int inet_get_free_port_socket_ipv4(int sock) +{ + struct sockaddr_in addr; + socklen_t len; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return -1; + } + + len = sizeof(addr); + if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { + return -1; + } + + return ntohs(addr.sin_port); +} + +static int inet_get_free_port_socket_ipv6(int sock) +{ + struct sockaddr_in6 addr; + socklen_t len; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = 0; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return -1; + } + + len = sizeof(addr); + if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { + return -1; + } + + return ntohs(addr.sin6_port); +} + +static int inet_get_free_port_multiple(int nb, int *port, bool ipv6) +{ + int sock[nb]; + int i; + + for (i = 0; i < nb; i++) { + sock[i] = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); + if (sock[i] < 0) { + break; + } + port[i] = ipv6 ? inet_get_free_port_socket_ipv6(sock[i]) : + inet_get_free_port_socket_ipv4(sock[i]); + if (port[i] == -1) { + break; + } + } + + nb = i; + for (i = 0; i < nb; i++) { + closesocket(sock[i]); + } + + return nb; +} + +static int inet_get_free_port(bool ipv6) +{ + int nb, port; + + nb = inet_get_free_port_multiple(1, &port, ipv6); + g_assert_cmpint(nb, ==, 1); + + return port; +} + +static void test_stream_inet_ipv4(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(false); + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_inet_ipv6(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(true); + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=::1,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=::1,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + + path = g_strconcat(tmpdir, "/stream_unix", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true," + "addr.type=unix,addr.path=%s,", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +#ifdef CONFIG_LINUX +static void test_stream_unix_abstract(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + + path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true," + "addr.type=unix,addr.path=%s," + "addr.abstract=on", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s,addr.abstract=on", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} +#endif + +#ifndef _WIN32 +static void test_stream_fd(void) +{ + QTestState *qts0, *qts1; + int sock[2]; + int ret; + + ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock); + g_assert_true(ret == 0); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,addr.type=fd,addr.str=%d", + sock[0]); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,addr.type=fd,addr.str=%d", + sock[1]); + + EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sock[0]); + closesocket(sock[1]); +} +#endif + +static void test_dgram_inet(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port[2]; + int nb; + + nb = inet_get_free_port_multiple(2, port, false); + g_assert_cmpint(nb, ==, 2); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "local.type=inet,local.host=127.0.0.1,local.port=%d," + "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", + port[0], port[1]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[0], port[1]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "local.type=inet,local.host=127.0.0.1,local.port=%d," + "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", + port[1], port[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[1], port[0]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +#ifndef _WIN32 +static void test_dgram_mcast(void) +{ + QTestState *qts; + + qts = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); + + EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); + + qtest_quit(qts); +} + +static void test_dgram_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path0, *path1; + + path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL); + path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path0, path1); + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path0, path1); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path1, path0); + + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path1, path0); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + unlink(path0); + g_free(path0); + unlink(path1); + g_free(path1); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_dgram_fd(void) +{ + QTestState *qts0, *qts1; + char *expect; + int ret; + int sv[2]; + + ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv); + g_assert_cmpint(ret, !=, -1); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[1]); + + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sv[0]); + closesocket(sv[1]); +} +#endif + +int main(int argc, char **argv) +{ + int ret; + bool has_ipv4, has_ipv6, has_afunix; + g_autoptr(GError) err = NULL; + + socket_init(); + g_test_init(&argc, &argv, NULL); + + if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + g_error("socket_check_protocol_support() failed\n"); + } + + tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err); + if (tmpdir == NULL) { + g_error("Can't create temporary directory in %s: %s", + g_get_tmp_dir(), err->message); + } + + if (has_ipv4) { + qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4); + qtest_add_func("/netdev/dgram/inet", test_dgram_inet); +#ifndef _WIN32 + qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); +#endif + } + if (has_ipv6) { + qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); + } + + socket_check_afunix_support(&has_afunix); + if (has_afunix) { +#ifndef _WIN32 + qtest_add_func("/netdev/dgram/unix", test_dgram_unix); +#endif + qtest_add_func("/netdev/stream/unix", test_stream_unix); +#ifdef CONFIG_LINUX + qtest_add_func("/netdev/stream/unix/abstract", + test_stream_unix_abstract); +#endif +#ifndef _WIN32 + qtest_add_func("/netdev/stream/fd", test_stream_fd); + qtest_add_func("/netdev/dgram/fd", test_dgram_fd); +#endif + } + + ret = g_test_run(); + + g_rmdir(tmpdir); + g_free(tmpdir); + + return ret; +} From e549227408732baf3546a92ed1a7c8743c5db175 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Jan 2023 13:25:57 +0100 Subject: [PATCH 238/814] tests/qtest/qom-test: Stop spamming the test log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are still facing the issues that our test logs in the gitlab CI are too big (and thus cut off). A huge part is still caused by the qom-test that prints the path and name of each object it looks at by default. That's too much. Let's be silent by default, and only print the object path+name when running with V=2 (and the properties only with V=3 and higher). Message-Id: <20230118122557.1668860-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/qtest/qom-test.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index d380261f8f..d677f87c8e 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -14,7 +14,7 @@ #include "qemu/cutils.h" #include "libqtest.h" -static bool verbose; +static int verbosity_level; static void test_properties(QTestState *qts, const char *path, bool recurse) { @@ -24,7 +24,9 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) QListEntry *entry; GSList *children = NULL, *links = NULL; - g_test_message("Obtaining properties of %s", path); + if (verbosity_level >= 2) { + g_test_message("Obtaining properties of %s", path); + } response = qtest_qmp(qts, "{ 'execute': 'qom-list'," " 'arguments': { 'path': %s } }", path); g_assert(response); @@ -51,7 +53,7 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) } } else { const char *prop = qdict_get_str(tuple, "name"); - if (verbose) { + if (verbosity_level >= 3) { g_test_message("-> %s", prop); } tmp = qtest_qmp(qts, @@ -109,8 +111,8 @@ int main(int argc, char **argv) { char *v_env = getenv("V"); - if (v_env && atoi(v_env) >= 2) { - verbose = true; + if (v_env) { + verbosity_level = atoi(v_env); } g_test_init(&argc, &argv, NULL); From a8fe0757e1a3b6d92d7d0a9ddccd902e35fbb045 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Jan 2023 13:51:32 +0100 Subject: [PATCH 239/814] tests/qtest/bios-tables-test: Make the test less verbose by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are facing the issues that our test logs in the gitlab CI are too big (and thus cut off). The bios-tables-test is one of the few qtests that prints many lines of output by default when running with V=1, so it contributes to this problem. Almost all other qtests are silent with V=1 and only print debug messages with V=2 and higher. Thus let's change the bios-tables-test to behave more like the other tests and only print the debug messages with V=2 (or higher). Message-Id: <20230118125132.1694469-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth --- tests/qtest/bios-tables-test.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 8608408213..355d0c3d56 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -24,7 +24,7 @@ * You will also notice that tests/qtest/bios-tables-test-allowed-diff.h lists * a bunch of files. This is your hint that you need to do the below: * 4. Run - * make check V=1 + * make check V=2 * this will produce a bunch of warnings about differences * beween actual and expected ACPI tables. If you have IASL installed, * they will also be disassembled so you can look at the disassembled @@ -108,6 +108,8 @@ static const char *iasl = CONFIG_IASL; static const char *iasl; #endif +static int verbosity_level; + static bool compare_signature(const AcpiSdtTable *sdt, const char *signature) { return !memcmp(sdt->aml, signature, 4); @@ -368,7 +370,7 @@ static GArray *load_expected_aml(test_data *data) gsize aml_len; GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); - if (getenv("V")) { + if (verbosity_level >= 2) { fputc('\n', stderr); } for (i = 0; i < data->tables->len; ++i) { @@ -383,7 +385,7 @@ static GArray *load_expected_aml(test_data *data) try_again: aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, sdt->aml, ext); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Looking for expected file '%s'\n", aml_file); } if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) { @@ -395,7 +397,7 @@ try_again: goto try_again; } g_assert(exp_sdt.aml_file); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Using expected file '%s'\n", aml_file); } ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml, @@ -503,7 +505,7 @@ static void test_acpi_asl(test_data *data) exp_sdt->aml, sdt->asl_file, sdt->aml_file, exp_sdt->asl_file, exp_sdt->aml_file); fflush(stderr); - if (getenv("V")) { + if (verbosity_level >= 1) { const char *diff_env = getenv("DIFF"); const char *diff_cmd = diff_env ? diff_env : "diff -U 16"; char *diff = g_strdup_printf("%s %s %s", diff_cmd, @@ -1974,8 +1976,13 @@ int main(int argc, char *argv[]) const char *arch = qtest_get_arch(); const bool has_kvm = qtest_has_accel("kvm"); const bool has_tcg = qtest_has_accel("tcg"); + char *v_env = getenv("V"); int ret; + if (v_env) { + verbosity_level = atoi(v_env); + } + g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { From e803a7f9b1f4d2324b15213593b6e24096e64280 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 12 Jan 2023 09:39:21 +0100 Subject: [PATCH 240/814] hw/misc/sifive_u_otp: Remove the deprecated OTP config with '-drive if=none' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit '-drive if=none' is meant for configuring back-end devices only, so this got marked as deprecated in QEMU 6.2. Users should now only use the new way with '-drive if=pflash' instead. Message-Id: <20230112083921.887828-1-thuth@redhat.com> Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 6 ------ docs/about/removed-features.rst | 7 +++++++ hw/misc/sifive_u_otp.c | 7 ------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 9f1bbc495d..3f4d678eb4 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -87,12 +87,6 @@ as short-form boolean values, and passed to plugins as ``arg_name=on``. However, short-form booleans are deprecated and full explicit ``arg_name=on`` form is preferred. -``-drive if=none`` for the sifive_u OTP device (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Using ``-drive if=none`` to configure the OTP device of the sifive_u -RISC-V machine is deprecated. Use ``-drive if=pflash`` instead. - ``-no-hpet`` (since 8.0) '''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 6c3aa5097f..a17d0554d6 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -422,6 +422,13 @@ the value is hexadecimal. That is, '0x20M' should be written either as ``tty`` and ``parport`` used to be aliases for ``serial`` and ``parallel`` respectively. The actual backend names should be used instead. +``-drive if=none`` for the sifive_u OTP device (removed in 8.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-drive if=pflash`` to configure the OTP device of the sifive_u +RISC-V machine instead. + + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index 6d7fdb040a..8965f5c22a 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -210,13 +210,6 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo) { - dinfo = drive_get(IF_NONE, 0, 0); - if (dinfo) { - warn_report("using \"-drive if=none\" for the OTP is deprecated, " - "use \"-drive if=pflash\" instead."); - } - } if (dinfo) { int ret; uint64_t perm; From ddf0944aa4b0c2d6516478a3e825149918b7a892 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 Jan 2023 13:57:45 +0100 Subject: [PATCH 241/814] configs/targets/nios2-softmmu: Add TARGET_NEED_FDT=y to the nios2 config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu-system-nios2 uses the functions from libfdt in hw/nios2/boot.c, so this target has to be marked with TARGET_NEED_FDT=y in its config file. Message-Id: <20230119125745.2028814-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- configs/targets/nios2-softmmu.mak | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/targets/nios2-softmmu.mak b/configs/targets/nios2-softmmu.mak index 1e93b54cd1..5823fc02c8 100644 --- a/configs/targets/nios2-softmmu.mak +++ b/configs/targets/nios2-softmmu.mak @@ -1,2 +1,3 @@ TARGET_ARCH=nios2 TARGET_ALIGNED_ONLY=y +TARGET_NEED_FDT=y From 769897bd0f4f9c2fe806d94d88aea1be85774342 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 20 Jan 2023 08:53:30 +0100 Subject: [PATCH 242/814] travis.yml: Use the libfdt from the distro instead of the submodule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to compile-test third party submodules over and over again if we can simply use the pre-build library from the distribution instead. By also adding --enable-fdt=system to the configure options, we can also avoid to check out the "dtc" submodule here. Message-Id: <20230120075330.2076773-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .travis.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb3baabca9..788e14c08c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,6 +128,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -149,7 +150,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false" - UNRELIABLE=true - name: "[ppc64] GCC check-tcg" @@ -162,6 +164,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -183,7 +186,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=ppc64-softmmu,ppc64le-linux-user" - name: "[s390x] GCC check-tcg" arch: s390x @@ -195,6 +199,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -216,7 +221,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" - UNRELIABLE=true script: - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? @@ -237,6 +243,7 @@ jobs: - libattr1-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgnutls28-dev - libiscsi-dev - liblttng-ust-dev @@ -255,8 +262,8 @@ jobs: # Tests dependencies - genisoimage env: - - CONFIG="--disable-containers --audio-drv-list=sdl --disable-user - --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + - CONFIG="--disable-containers --enable-fdt=system --audio-drv-list=sdl + --disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" - name: "[s390x] GCC (user)" arch: s390x @@ -281,6 +288,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -300,6 +308,6 @@ jobs: - ninja-build env: - TEST_CMD="make check-unit" - - CONFIG="--disable-containers --disable-tcg --enable-kvm - --disable-tools --host-cc=clang --cxx=clang++" + - CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools + --enable-fdt=system --host-cc=clang --cxx=clang++" - UNRELIABLE=true From 5b5b0c73c8264647db9f4dcbb2894b685512a139 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 19 Jan 2023 14:59:14 +0100 Subject: [PATCH 243/814] travis.yml: Remove the generic addons section Each job uses its own addons section nowadays, so the generic section is completely unused and outdated, thus we can remove it now. Message-Id: <20230119135914.2040853-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- .travis.yml | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index 788e14c08c..cf088ba4cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,43 +16,6 @@ cache: - $HOME/avocado/data/cache -addons: - apt: - packages: - # Build dependencies - - libaio-dev - - libattr1-dev - - libbrlapi-dev - - libcap-ng-dev - - libcacard-dev - - libgcc-7-dev - - libgnutls28-dev - - libgtk-3-dev - - libiscsi-dev - - liblttng-ust-dev - - libncurses5-dev - - libnfs-dev - - libpixman-1-dev - - libpng-dev - - librados-dev - - libsdl2-dev - - libsdl2-image-dev - - libseccomp-dev - - libspice-protocol-dev - - libspice-server-dev - - libssh-dev - - liburcu-dev - - libusb-1.0-0-dev - - libvdeplug-dev - - libvte-2.91-dev - - libzstd-dev - - ninja-build - - sparse - - uuid-dev - # Tests dependencies - - genisoimage - - # The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu # to prevent IRC notifications from forks. This was created using: # $ travis encrypt -r "qemu/qemu" "irc.oftc.net#qemu" From 2b5e0c9ff8299bbfa1a6b0c9cac385adb733152a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 24 Jan 2023 15:38:24 +0100 Subject: [PATCH 244/814] tests/docker/dockerfiles: Add libfdt to the i386 and to the riscv64 container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to recompile the dtc submodule here again and again, we can use the pre-built binary from the distribution instead. (And this will also help in case we finally get rid of the dtc submodule in QEMU one day) Message-Id: <20230124143824.844040-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/docker/dockerfiles/debian-riscv64-cross.docker | 1 + tests/docker/dockerfiles/fedora-i386-cross.docker | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 9715791e0b..3daf93968a 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -42,6 +42,7 @@ RUN apt update && \ apt install -y --no-install-recommends \ gcc-riscv64-linux-gnu \ libc6-dev-riscv64-cross \ + libfdt-dev:riscv64 \ libffi-dev:riscv64 \ libglib2.0-dev:riscv64 \ libpixman-1-dev:riscv64 diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 7eec648d2d..f58b64dc3e 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -9,6 +9,7 @@ ENV PACKAGES \ findutils \ gcc \ git \ + libfdt-devel.i686 \ libffi-devel.i686 \ libselinux-devel.i686 \ libtasn1-devel.i686 \ From 6366ca31ef31bb69d30356c736bf902f15c1c792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:42 +0100 Subject: [PATCH 245/814] qemu/bswap: Replace bswapXX() by compiler __builtin_bswap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the compiler built-in function to byte swap values, as the compiler is clever and will fold constants. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230111163147.71761-2-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 346d05f2aa..ca2b4c3f15 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -37,31 +37,12 @@ static inline uint64_t bswap64(uint64_t x) #endif #ifdef BSWAP_FROM_FALLBACKS -static inline uint16_t bswap16(uint16_t x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -static inline uint32_t bswap32(uint32_t x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - -static inline uint64_t bswap64(uint64_t x) -{ - return (((x & 0x00000000000000ffULL) << 56) | - ((x & 0x000000000000ff00ULL) << 40) | - ((x & 0x0000000000ff0000ULL) << 24) | - ((x & 0x00000000ff000000ULL) << 8) | - ((x & 0x000000ff00000000ULL) >> 8) | - ((x & 0x0000ff0000000000ULL) >> 24) | - ((x & 0x00ff000000000000ULL) >> 40) | - ((x & 0xff00000000000000ULL) >> 56)); -} +#undef bswap16 +#define bswap16(_x) __builtin_bswap16(_x) +#undef bswap32 +#define bswap32(_x) __builtin_bswap32(_x) +#undef bswap64 +#define bswap64(_x) __builtin_bswap64(_x) #endif #undef BSWAP_FROM_BYTESWAP From b1032a23edf9c6af2bdfdf8f542f86221a75676b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:43 +0100 Subject: [PATCH 246/814] qemu/bswap: Replace bswapXXs() by compiler __builtin_bswap() 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: <20230111163147.71761-3-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index ca2b4c3f15..d2dafdc54c 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -50,29 +50,31 @@ static inline uint64_t bswap64(uint64_t x) static inline void bswap16s(uint16_t *s) { - *s = bswap16(*s); + *s = __builtin_bswap16(*s); } static inline void bswap32s(uint32_t *s) { - *s = bswap32(*s); + *s = __builtin_bswap32(*s); } static inline void bswap64s(uint64_t *s) { - *s = bswap64(*s); + *s = __builtin_bswap64(*s); } #if HOST_BIG_ENDIAN #define be_bswap(v, size) (v) -#define le_bswap(v, size) glue(bswap, size)(v) +#define le_bswap(v, size) glue(__builtin_bswap, size)(v) #define be_bswaps(v, size) -#define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) +#define le_bswaps(p, size) \ + do { *p = glue(__builtin_bswap, size)(*p); } while (0) #else #define le_bswap(v, size) (v) -#define be_bswap(v, size) glue(bswap, size)(v) +#define be_bswap(v, size) glue(__builtin_bswap, size)(v) #define le_bswaps(v, size) -#define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) +#define be_bswaps(p, size) \ + do { *p = glue(__builtin_bswap, size)(*p); } while (0) #endif /** From e76ce15db7ea9542fbb962b12a8ac738b57b73cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:44 +0100 Subject: [PATCH 247/814] qemu/bswap: Remove dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit efc6c070aca ("configure: Add a test for the minimum compiler version") the minimum compiler version required for GCC is 4.8, which supports __builtin_bswap(). Drop the dependency. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230111163147.71761-4-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 21 --------------------- meson.build | 2 -- 2 files changed, 23 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index d2dafdc54c..fd5a98125a 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -8,9 +8,6 @@ # include #elif defined(__HAIKU__) # include -#elif defined(CONFIG_BYTESWAP_H) -# include -#define BSWAP_FROM_BYTESWAP # else #define BSWAP_FROM_FALLBACKS #endif /* ! CONFIG_MACHINE_BSWAP_H */ @@ -19,23 +16,6 @@ extern "C" { #endif -#ifdef BSWAP_FROM_BYTESWAP -static inline uint16_t bswap16(uint16_t x) -{ - return bswap_16(x); -} - -static inline uint32_t bswap32(uint32_t x) -{ - return bswap_32(x); -} - -static inline uint64_t bswap64(uint64_t x) -{ - return bswap_64(x); -} -#endif - #ifdef BSWAP_FROM_FALLBACKS #undef bswap16 #define bswap16(_x) __builtin_bswap16(_x) @@ -45,7 +25,6 @@ static inline uint64_t bswap64(uint64_t x) #define bswap64(_x) __builtin_bswap64(_x) #endif -#undef BSWAP_FROM_BYTESWAP #undef BSWAP_FROM_FALLBACKS static inline void bswap16s(uint16_t *s) diff --git a/meson.build b/meson.build index 6d3b665629..7e15a010bf 100644 --- a/meson.build +++ b/meson.build @@ -2013,8 +2013,6 @@ if rdma.found() endif # has_header_symbol -config_host_data.set('CONFIG_BYTESWAP_H', - cc.has_header_symbol('byteswap.h', 'bswap_32')) config_host_data.set('CONFIG_EPOLL_CREATE1', cc.has_header_symbol('sys/epoll.h', 'epoll_create1')) config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE', From 91fdbf6dfae20c5e409f82f75776f688ae71c6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:45 +0100 Subject: [PATCH 248/814] qemu/bswap: Use compiler __builtin_bswap() on Haiku MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit efc6c070aca ("configure: Add a test for the minimum compiler version") the minimum compiler version required for GCC is 4.8, which supports __builtin_bswap(). Remove the Haiku specific ifdef'ry. This reverts commit 652a46ebba970017c7a23767dcc983265cdb8eb7 ("bswap.h: Include on Haiku for bswap operations"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230111163147.71761-5-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index fd5a98125a..8cd5a2b02e 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -6,8 +6,6 @@ # include #elif defined(__FreeBSD__) # include -#elif defined(__HAIKU__) -# include # else #define BSWAP_FROM_FALLBACKS #endif /* ! CONFIG_MACHINE_BSWAP_H */ From a97cfd56d956de0a24cb0d1c86d05e4545eb6fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:46 +0100 Subject: [PATCH 249/814] qemu/bswap: Use compiler __builtin_bswap() on FreeBSD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit efc6c070aca ("configure: Add a test for the minimum compiler version") the minimum compiler version required for GCC is 4.8, which supports __builtin_bswap(). Remove the FreeBSD specific ifdef'ry. This reverts commit de03c3164accc21311c39327601fcdd95da301f3 ("bswap: Fix build on FreeBSD 10.0"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230111163147.71761-6-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 8cd5a2b02e..32d5cdec27 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -4,8 +4,6 @@ #ifdef CONFIG_MACHINE_BSWAP_H # include # include -#elif defined(__FreeBSD__) -# include # else #define BSWAP_FROM_FALLBACKS #endif /* ! CONFIG_MACHINE_BSWAP_H */ From ec6bf79d7d44059ccba16bf883b700c7d69cebb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 11 Jan 2023 17:31:47 +0100 Subject: [PATCH 250/814] qemu/bswap: Use compiler __builtin_bswap() on NetBSD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit efc6c070aca ("configure: Add a test for the minimum compiler version") the minimum compiler version required for GCC is 4.8, which supports __builtin_bswap(). Remove the NetBSD specific ifdef'ry. This reverts commit 1360677cfe3ca8f945fa1de77823df21a77e4500 ("makes NetBSD use the native bswap functions"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230111163147.71761-7-philmd@linaro.org> Signed-off-by: Thomas Huth --- include/qemu/bswap.h | 11 ----------- meson.build | 4 ---- 2 files changed, 15 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 32d5cdec27..3cbe52246b 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,27 +1,16 @@ #ifndef BSWAP_H #define BSWAP_H -#ifdef CONFIG_MACHINE_BSWAP_H -# include -# include -# else -#define BSWAP_FROM_FALLBACKS -#endif /* ! CONFIG_MACHINE_BSWAP_H */ - #ifdef __cplusplus extern "C" { #endif -#ifdef BSWAP_FROM_FALLBACKS #undef bswap16 #define bswap16(_x) __builtin_bswap16(_x) #undef bswap32 #define bswap32(_x) __builtin_bswap32(_x) #undef bswap64 #define bswap64(_x) __builtin_bswap64(_x) -#endif - -#undef BSWAP_FROM_FALLBACKS static inline void bswap16s(uint16_t *s) { diff --git a/meson.build b/meson.build index 7e15a010bf..a03d3dbd3a 100644 --- a/meson.build +++ b/meson.build @@ -2030,10 +2030,6 @@ config_host_data.set('CONFIG_INOTIFY', cc.has_header_symbol('sys/inotify.h', 'inotify_init')) config_host_data.set('CONFIG_INOTIFY1', cc.has_header_symbol('sys/inotify.h', 'inotify_init1')) -config_host_data.set('CONFIG_MACHINE_BSWAP_H', - cc.has_header_symbol('machine/bswap.h', 'bswap32', - prefix: '''#include - #include ''')) config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK', cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK')) config_host_data.set('CONFIG_RTNETLINK', From 73741fda6ce7d013f5c8ec83d2665fda03a74a15 Mon Sep 17 00:00:00 2001 From: Wenchao Wang Date: Thu, 19 Jan 2023 20:08:37 +0800 Subject: [PATCH 251/814] MAINTAINERS: Abort HAXM maintenance Abort the maintenance of Guest CPU Cores (HAXM). * Clean up the maintainer list of X86 HAXM CPUs * Remove the web page URL and the mailing list * Change the status to Orphan Reviewed-by: Hang Yuan Signed-off-by: Wenchao Wang Message-Id: Signed-off-by: Thomas Huth --- MAINTAINERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c581c11a64..307a9d5d4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -500,10 +500,7 @@ F: stubs/xen-hw-stub.c Guest CPU Cores (HAXM) --------------------- X86 HAXM CPUs -M: Wenchao Wang -L: haxm-team@intel.com -W: https://github.com/intel/haxm/issues -S: Maintained +S: Orphan F: accel/stubs/hax-stub.c F: include/sysemu/hax.h F: target/i386/hax/ From 90c167a1da5e35e3681a9ae5bcddcab707086d9a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 26 Jan 2023 13:10:34 +0100 Subject: [PATCH 252/814] docs/about/deprecated: Mark HAXM in QEMU as deprecated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HAXM project has been retired (see https://github.com/intel/haxm#status), so we should mark the code in QEMU as deprecated (and finally remove it unless somebody else picks the project up again - which is quite unlikely since there are now whpx and hvf on these operating systems, too). Message-Id: <20230126121034.1035138-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 6 ++++++ target/i386/hax/hax-all.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 3f4d678eb4..da2e6fe63d 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -93,6 +93,12 @@ form is preferred. The HPET setting has been turned into a machine property. Use ``-machine hpet=off`` instead. +``-accel hax`` (since 8.0) +'''''''''''''''''''''''''' + +The HAXM project has been retired (see https://github.com/intel/haxm#status). +Use "whpx" (on Windows) or "hvf" (on macOS) instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c index b7fb5385b2..3e5992a63b 100644 --- a/target/i386/hax/hax-all.c +++ b/target/i386/hax/hax-all.c @@ -357,6 +357,9 @@ static int hax_accel_init(MachineState *ms) fprintf(stdout, "HAX is %s and emulator runs in %s mode.\n", !ret ? "working" : "not working", !ret ? "fast virt" : "emulation"); + fprintf(stdout, + "NOTE: HAX is deprecated and will be removed in a future release.\n" + " Use 'whpx' (on Windows) or 'hvf' (on macOS) instead.\n"); } return ret; } From c0031d389e7cc16b0223dbf5994627a4b9b44df3 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Fri, 20 Jan 2023 15:48:22 -0300 Subject: [PATCH 253/814] tests/tcg: Do not build/run TCG tests if TCG is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tests under tests/tcg depend on the TCG accelerator. Do not build them if --disable-tcg was given in the configure line. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230120184825.31626-7-farosas@suse.de> Signed-off-by: Thomas Huth --- configure | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 9e407ce2e3..64960c6000 100755 --- a/configure +++ b/configure @@ -2483,7 +2483,11 @@ for target in $target_list; do tcg_tests_targets="$tcg_tests_targets $target" fi done -echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> config-host.mak) + +if test "$tcg" = "enabled"; then + echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> config-host.mak +fi +) if test "$skip_meson" = no; then cross="config-meson.cross.new" From 6c25794fa36fe3fa483c6392c44ae68692aabb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Jan 2023 13:05:12 +0100 Subject: [PATCH 254/814] tests/qtest/vnc-display-test: Suppress build warnings on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While this test is skipped on Windows, we still get when building: tests/qtest/vnc-display-test.c:22:20: warning: unused function 'on_vnc_error' [-Wunused-function] static inline void on_vnc_error(VncConnection* self, ^ tests/qtest/vnc-display-test.c:28:20: warning: unused function 'on_vnc_auth_failure' [-Wunused-function] static inline void on_vnc_auth_failure(VncConnection *self, ^ 2 warnings generated. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230119120514.28778-2-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Marc-André Lureau Signed-off-by: Thomas Huth --- tests/qtest/vnc-display-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/vnc-display-test.c b/tests/qtest/vnc-display-test.c index e2a9d682bb..fd63e3a881 100644 --- a/tests/qtest/vnc-display-test.c +++ b/tests/qtest/vnc-display-test.c @@ -19,6 +19,8 @@ typedef struct Test { GMainLoop *loop; } Test; +#if !defined(WIN32) + static void on_vnc_error(VncConnection* self, const char* msg) { @@ -31,6 +33,8 @@ static void on_vnc_auth_failure(VncConnection *self, g_error("vnc-auth-failure: %s", msg); } +#endif + static bool test_setup(Test *test) { From fe843ea21889236f41a96590513b042e59032a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Jan 2023 13:05:13 +0100 Subject: [PATCH 255/814] tests/qtest/vnc-display-test: Use the 'none' machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we don't specify any machine, an architecture default might be picked. But some architectures don't provide any default, such ARM: $ make check-qtest-aarch64 ... 19/20 qemu:qtest+qtest-aarch64 / qtest-aarch64/vnc-display-test qemu-system-aarch64: No machine specified, and there is no default Since we don't need any particular machine to run this VNC test, use the 'none' machine. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230119120514.28778-3-philmd@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Fabiano Rosas Reviewed-by: Marc-André Lureau Signed-off-by: Thomas Huth --- tests/qtest/vnc-display-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/vnc-display-test.c b/tests/qtest/vnc-display-test.c index fd63e3a881..df468c7b22 100644 --- a/tests/qtest/vnc-display-test.c +++ b/tests/qtest/vnc-display-test.c @@ -44,7 +44,7 @@ test_setup(Test *test) #else int pair[2]; - test->qts = qtest_init("-vnc none -name vnc-test"); + test->qts = qtest_init("-M none -vnc none -name vnc-test"); g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); From 2a969c0cbcf575a4c839d60e6ed71bbb9e469fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Jan 2023 13:05:14 +0100 Subject: [PATCH 256/814] tests/qtest/vnc-display-test: Disable on Darwin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test is failing in gtk-vnc on Darwin: $ make check-qtest-aarch64 ... 19/20 qemu:qtest+qtest-aarch64 / qtest-aarch64/vnc-display-test ERROR **: 10:42:35.488: vnc-error: Unsupported auth type 17973672 While QEMU picks the sigaltstack coroutine backend, gtk-vnc uses the ucontext coroutine backend, which might be broken on Darwin. Disable this test (current problem being investigated in this thread: https://lore.kernel.org/qemu-devel/Y8kw6X6keB5l53nl@redhat.com/). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230119120514.28778-4-philmd@linaro.org> Reviewed-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Signed-off-by: Thomas Huth --- tests/qtest/vnc-display-test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/qtest/vnc-display-test.c b/tests/qtest/vnc-display-test.c index df468c7b22..e52a4326ec 100644 --- a/tests/qtest/vnc-display-test.c +++ b/tests/qtest/vnc-display-test.c @@ -19,7 +19,7 @@ typedef struct Test { GMainLoop *loop; } Test; -#if !defined(WIN32) +#if !defined(WIN32) && !defined(CONFIG_DARWIN) static void on_vnc_error(VncConnection* self, const char* msg) @@ -41,6 +41,9 @@ test_setup(Test *test) #ifdef WIN32 g_test_skip("Not supported on Windows yet"); return false; +#elif defined(CONFIG_DARWIN) + g_test_skip("Broken on Darwin"); + return false; #else int pair[2]; From a4267f00925301e908484050fab559c93bee5a1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 20 Jan 2023 09:23:31 +0100 Subject: [PATCH 257/814] tests/qtest/boot-serial-test: Constify tests[] array 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: <20230120082341.59913-2-philmd@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/boot-serial-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index b216519b62..3aef3a97a9 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -139,7 +139,7 @@ typedef struct testdef { const uint8_t *bios; /* Set in case we use our own mini bios */ } testdef_t; -static testdef_t tests[] = { +static const testdef_t tests[] = { { "alpha", "clipper", "", "PCI:" }, { "avr", "arduino-duemilanove", "", "T", sizeof(bios_avr), NULL, bios_avr }, { "avr", "arduino-mega-2560-v3", "", "T", sizeof(bios_avr), NULL, bios_avr}, From 9ce75d4d5eaf30333797fd6f8b5c6ee7f917951f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 17 Nov 2022 00:44:58 +0300 Subject: [PATCH 258/814] shpc: disallow unplug when power indicator is blinking Pressing attention button has special meaning when power indicator is blinking. Better just not do it. For example, trying to remove device immediately after hotplug leads to both commands succeded but device not actually unrealized. Same thing for PCIE hotplug was done in 81124b3c7a5dae "pcie: add power indicator blink check" Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20221116214458.82090-1-vsementsov@yandex-team.ru> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/shpc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index e71f3a7483..fca7f6691a 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -568,6 +568,13 @@ void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev, state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); + + if (led == SHPC_LED_BLINK) { + error_setg(errp, "Hot-unplug failed: " + "guest is busy (power indicator blinking)"); + return; + } + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { shpc_free_devices_in_slot(shpc, slot); shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); From 1f1b30af753288c176ddff2bc62b6d3d37aa8a6d Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 21 Jan 2023 16:19:35 +0100 Subject: [PATCH 259/814] hw/i386/acpi-build: Remove unused attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ammends commit 3db119da7915 'pc: acpi: switch to AML API composed DSDT'. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Message-Id: <20230121151941.24120-2-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 127c4e2d50..8c333973f9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -117,8 +117,6 @@ typedef struct AcpiMiscInfo { #ifdef CONFIG_TPM TPMVersion tpm_version; #endif - const unsigned char *dsdt_code; - unsigned dsdt_size; } AcpiMiscInfo; typedef struct FwCfgTPMConfig { From 9c6c0aeacda7d9c3e3d5743f4927d31f5ac76888 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 21 Jan 2023 16:19:36 +0100 Subject: [PATCH 260/814] hw/isa/isa-bus: Turn isa_build_aml() into qbus_build_aml() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frees isa-bus.c from implicit ACPI dependency. While at it, resolve open coding of qbus_build_aml() in piix3 and ich9. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Message-Id: <20230121151941.24120-3-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/acpi_interface.c | 10 ++++++++++ hw/i2c/smbus_ich9.c | 5 +---- hw/i386/acpi-microvm.c | 3 ++- hw/isa/isa-bus.c | 10 ---------- hw/isa/lpc_ich9.c | 5 +---- hw/isa/piix3.c | 5 +---- include/hw/acpi/acpi_aml_interface.h | 3 +++ include/hw/isa/isa.h | 1 - 8 files changed, 18 insertions(+), 24 deletions(-) diff --git a/hw/acpi/acpi_interface.c b/hw/acpi/acpi_interface.c index c668d361f6..8637ff18fc 100644 --- a/hw/acpi/acpi_interface.c +++ b/hw/acpi/acpi_interface.c @@ -2,6 +2,7 @@ #include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/acpi_aml_interface.h" #include "qemu/module.h" +#include "qemu/queue.h" void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) { @@ -12,6 +13,15 @@ void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) } } +void qbus_build_aml(BusState *bus, Aml *scope) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + call_dev_aml_func(DEVICE(kid->child), scope); + } +} + static void register_types(void) { static const TypeInfo acpi_dev_if_info = { diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index ee50ba1f2c..52ba77f3fc 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -97,13 +97,10 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp) static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope) { - BusChild *kid; ICH9SMBState *s = ICH9_SMB_DEVICE(adev); BusState *bus = BUS(s->smb.smbus); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void ich9_smb_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index fb09185cbd..a075360d85 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -26,6 +26,7 @@ #include "exec/memory.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" @@ -129,7 +130,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker, sb_scope = aml_scope("_SB"); fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg); - isa_build_aml(ISA_BUS(isabus), sb_scope); + qbus_build_aml(BUS(isabus), sb_scope); build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev, GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE); acpi_dsdt_add_power_button(sb_scope); diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 1bee1a47f1..f155b80010 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -24,7 +24,6 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/isa/isa.h" -#include "hw/acpi/acpi_aml_interface.h" static ISABus *isabus; @@ -188,15 +187,6 @@ ISADevice *isa_vga_init(ISABus *bus) } } -void isa_build_aml(ISABus *bus, Aml *scope) -{ - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } -} - static void isabus_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 8d541e2b54..1fba3c210c 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -813,7 +813,6 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) { Aml *field; - BusChild *kid; ICH9LPCState *s = ICH9_LPC_DEVICE(adev); BusState *bus = BUS(s->isa_bus); Aml *sb_scope = aml_scope("\\_SB"); @@ -835,9 +834,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(sb_scope, field); aml_append(scope, sb_scope); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void ich9_lpc_class_init(ObjectClass *klass, void *data) diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 283b971ec4..a9cb39bf21 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -306,7 +306,6 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) { Aml *field; - BusChild *kid; Aml *sb_scope = aml_scope("\\_SB"); BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0"); @@ -322,9 +321,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(sb_scope, field); aml_append(scope, sb_scope); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void pci_piix3_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/acpi/acpi_aml_interface.h b/include/hw/acpi/acpi_aml_interface.h index 436da069d6..11748a8866 100644 --- a/include/hw/acpi/acpi_aml_interface.h +++ b/include/hw/acpi/acpi_aml_interface.h @@ -3,6 +3,7 @@ #include "qom/object.h" #include "hw/acpi/aml-build.h" +#include "hw/qdev-core.h" #define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface" typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass; @@ -46,4 +47,6 @@ static inline void call_dev_aml_func(DeviceState *dev, Aml *scope) } } +void qbus_build_aml(BusState *bus, Aml *scope); + #endif diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 6c8a8a92cb..25acd5c34c 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -86,7 +86,6 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp); ISADevice *isa_create_simple(ISABus *bus, const char *name); ISADevice *isa_vga_init(ISABus *bus); -void isa_build_aml(ISABus *bus, Aml *scope); /** * isa_register_ioport: Install an I/O port region on the ISA bus. From edfa7180106162765a75f7be17be8df0e4ab823e Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 21 Jan 2023 16:19:37 +0100 Subject: [PATCH 261/814] hw/acpi/piix4: No need to #include "hw/southbridge/piix.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw/acpi/piix4 has its own header with its structure definition etc. Ammends commit 2bfd0845f0 'hw/acpi/piix4: move PIIX4PMState into separate piix4.h header'. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230121151941.24120-4-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/piix4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 0a81f1ad93..2ab4930f11 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" -#include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/isa/apm.h" #include "hw/i2c/pm_smbus.h" From d395b18dce82855d03d934e30a515caf5a10a885 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Sat, 21 Jan 2023 16:19:38 +0100 Subject: [PATCH 262/814] hw/acpi/acpi_dev_interface: Remove unused parameter from AcpiDeviceIfClass::madt_cpu The only function ever assigned to AcpiDeviceIfClass::madt_cpu is pc_madt_cpu_entry() which doesn't use the AcpiDeviceIf parameter. Signed-off-by: Bernhard Beschow Reviewed-by: Igor Mammedov Message-Id: <20230121151941.24120-5-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/acpi-x86-stub.c | 5 ++--- hw/acpi/cpu.c | 3 +-- hw/i386/acpi-common.c | 7 +++---- include/hw/acpi/acpi_dev_interface.h | 3 +-- include/hw/i386/pc.h | 6 ++---- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/hw/acpi/acpi-x86-stub.c b/hw/acpi/acpi-x86-stub.c index 3df1e090f4..d0d399d26b 100644 --- a/hw/acpi/acpi-x86-stub.c +++ b/hw/acpi/acpi-x86-stub.c @@ -2,9 +2,8 @@ #include "hw/i386/pc.h" #include "hw/i386/acpi-build.h" -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled) +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled) { } diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 4e580959a2..19c154d78f 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -355,7 +355,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root); Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); cpu_ctrl_dev = aml_device("%s", cphp_res_path); { @@ -666,7 +665,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, /* build _MAT object */ assert(adevc && adevc->madt_cpu); - adevc->madt_cpu(adev, i, arch_ids, madt_buf, + adevc->madt_cpu(i, arch_ids, madt_buf, true); /* set enabled flag */ aml_append(dev, aml_name_decl("_MAT", aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 4aaafbdd7b..52e5c1439a 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -33,9 +33,8 @@ #include "acpi-build.h" #include "acpi-common.h" -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled) +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled) { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ @@ -112,7 +111,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(adev, i, apic_ids, table_data, false); + adevc->madt_cpu(i, apic_ids, table_data, false); if (apic_ids->cpus[i].arch_id > 254) { x2apic_mode = true; } diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h index ea6056ab92..a1648220ff 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -52,8 +52,7 @@ struct AcpiDeviceIfClass { /* */ void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev); - void (*madt_cpu)(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, + void (*madt_cpu)(int uid, const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); }; #endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 88a120bc23..66e3d059ef 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -9,7 +9,6 @@ #include "hw/block/flash.h" #include "hw/i386/x86.h" -#include "hw/acpi/acpi_dev_interface.h" #include "hw/hotplug.h" #include "qom/object.h" #include "hw/i386/sgx-epc.h" @@ -193,9 +192,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); /* hw/i386/acpi-common.c */ -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled); +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled); /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); From 744734ccc9eff28394a453de462b2a155f364118 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 9 Jan 2023 15:31:30 +0900 Subject: [PATCH 263/814] vhost-user: Correct a reference of TARGET_AARCH64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Presumably TARGET_ARM_64 should be a mistake of TARGET_AARCH64. Signed-off-by: Akihiko Odaki Message-Id: <20230109063130.81296-1-akihiko.odaki@daynix.com> Fixes: 27598393a2 ("Lift max memory slots limit imposed by vhost-user") Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index d9ce0501b2..6c79da953b 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -48,7 +48,7 @@ * hardware plaform. */ #if defined(TARGET_X86) || defined(TARGET_X86_64) || \ - defined(TARGET_ARM) || defined(TARGET_ARM_64) + defined(TARGET_ARM) || defined(TARGET_AARCH64) #include "hw/acpi/acpi.h" #define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS From 8a8c9c3a747f77e664fa2288735b45a9d750be75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Jan 2023 18:37:02 +0100 Subject: [PATCH 264/814] hw/pci-host: Use register definitions from PCI standard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to document magic values when the definition names from "standard-headers/linux/pci_regs.h" are self-explicit. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230105173702.56610-1-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: BALATON Zoltan Reviewed-by: Richard Henderson Reviewed-by: Bernhard Beschow --- hw/pci-host/grackle.c | 2 +- hw/pci-host/raven.c | 6 +++--- hw/pci-host/uninorth.c | 33 +++++++++++---------------------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 8cf318cb80..8e589ff2c9 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -91,7 +91,7 @@ static void grackle_init(Object *obj) static void grackle_pci_realize(PCIDevice *d, Error **errp) { - d->config[0x09] = 0x01; + d->config[PCI_CLASS_PROG] = 0x01; } static void grackle_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index 5b00b4e462..cdfb62ac2e 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -330,9 +330,9 @@ static void raven_realize(PCIDevice *d, Error **errp) char *filename; int bios_size = -1; - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x34] = 0x00; // capabilities_pointer + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE, &error_fatal); diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index e3abe3c0f9..e4c1abd871 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -276,12 +276,9 @@ static void pci_unin_internal_init(Object *obj) static void unin_main_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer */ - d->config[0x34] = 0x00; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; /* * Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI @@ -296,30 +293,22 @@ static void unin_main_pci_host_realize(PCIDevice *d, Error **errp) static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer - d->config[0x34] = 0x80; */ + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + /* d->config[PCI_CAPABILITY_LIST] = 0x80; */ } static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache line size */ - d->config[0x0C] = 0x08; - /* latency timer */ - d->config[0x0D] = 0x10; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; } static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer */ - d->config[0x34] = 0x00; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; } static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) From bad9c5a5166fd5e3a892b7b0477cf2f4bd3a959a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 9 Jan 2023 10:58:09 +0000 Subject: [PATCH 265/814] virtio-rng-pci: fix migration compat for vectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixup the migration compatibility for existing machine types so that they do not enable msi-x. Symptom: (qemu) qemu: get_pci_config_device: Bad config data: i=0x34 read: 84 device: 98 cmask: ff wmask: 0 w1cmask:0 qemu: Failed to load PCIDevice:config qemu: Failed to load virtio-rng:virtio qemu: error while loading state for instance 0x0 of device '0000:00:03.0/virtio-rng' qemu: load of migration failed: Invalid argument Note: This fix will break migration from 7.2->7.2-fixed with this patch bz: https://bugzilla.redhat.com/show_bug.cgi?id=2155749 Fixes: 9ea02e8f1 ("virtio-rng-pci: Allow setting nvectors, so we can use MSI-X") Signed-off-by: Dr. David Alan Gilbert Message-Id: <20230109105809.163975-1-dgilbert@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Thomas Huth Acked-by: David Daney Fixes: 9ea02e8f1 ("virtio-rng-pci: Allow setting nvectors, so we can use MSI-X")
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé --- hw/core/machine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 616f3a207c..f7761baab5 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -46,6 +46,7 @@ const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2); GlobalProperty hw_compat_7_1[] = { { "virtio-device", "queue_reset", "false" }, + { "virtio-rng-pci", "vectors", "0" }, }; const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1); From 8a7c606016d283a1716290c657f6f45bc7c4d817 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 9 Jan 2023 14:37:27 -0500 Subject: [PATCH 266/814] intel-iommu: Document iova_tree It seems not super clear on when iova_tree is used, and why. Add a rich comment above iova_tree to track why we needed the iova_tree, and when we need it. Also comment for the map/unmap messages, on how they're used and implications (e.g. unmap can be larger than the mapped ranges). Suggested-by: Jason Wang Signed-off-by: Peter Xu Message-Id: <20230109193727.1360190-1-peterx@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/exec/memory.h | 26 ++++++++++++++++++++++++ include/hw/i386/intel_iommu.h | 38 ++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index c37ffdbcd1..2e602a2fad 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -129,6 +129,32 @@ struct IOMMUTLBEntry { /* * Bitmap for different IOMMUNotifier capabilities. Each notifier can * register with one or multiple IOMMU Notifier capability bit(s). + * + * Normally there're two use cases for the notifiers: + * + * (1) When the device needs accurate synchronizations of the vIOMMU page + * tables, it needs to register with both MAP|UNMAP notifies (which + * is defined as IOMMU_NOTIFIER_IOTLB_EVENTS below). + * + * Regarding to accurate synchronization, it's when the notified + * device maintains a shadow page table and must be notified on each + * guest MAP (page table entry creation) and UNMAP (invalidation) + * events (e.g. VFIO). Both notifications must be accurate so that + * the shadow page table is fully in sync with the guest view. + * + * (2) When the device doesn't need accurate synchronizations of the + * vIOMMU page tables, it needs to register only with UNMAP or + * DEVIOTLB_UNMAP notifies. + * + * It's when the device maintains a cache of IOMMU translations + * (IOTLB) and is able to fill that cache by requesting translations + * from the vIOMMU through a protocol similar to ATS (Address + * Translation Service). + * + * Note that in this mode the vIOMMU will not maintain a shadowed + * page table for the address space, and the UNMAP messages can cover + * more than the pages that used to get mapped. The IOMMU notifiee + * should be able to take care of over-sized invalidations. */ typedef enum { IOMMU_NOTIFIER_NONE = 0, diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 46d973e629..89dcbc5e1e 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -109,7 +109,43 @@ struct VTDAddressSpace { QLIST_ENTRY(VTDAddressSpace) next; /* Superset of notifier flags that this address space has */ IOMMUNotifierFlag notifier_flags; - IOVATree *iova_tree; /* Traces mapped IOVA ranges */ + /* + * @iova_tree traces mapped IOVA ranges. + * + * The tree is not needed if no MAP notifier is registered with current + * VTD address space, because all guest invalidate commands can be + * directly passed to the IOMMU UNMAP notifiers without any further + * reshuffling. + * + * The tree OTOH is required for MAP typed iommu notifiers for a few + * reasons. + * + * Firstly, there's no way to identify whether an PSI (Page Selective + * Invalidations) or DSI (Domain Selective Invalidations) event is an + * MAP or UNMAP event within the message itself. Without having prior + * knowledge of existing state vIOMMU doesn't know whether it should + * notify MAP or UNMAP for a PSI message it received when caching mode + * is enabled (for MAP notifiers). + * + * Secondly, PSI messages received from guest driver can be enlarged in + * range, covers but not limited to what the guest driver wanted to + * invalidate. When the range to invalidates gets bigger than the + * limit of a PSI message, it can even become a DSI which will + * invalidate the whole domain. If the vIOMMU directly notifies the + * registered device with the unmodified range, it may confuse the + * registered drivers (e.g. vfio-pci) on either: + * + * (1) Trying to map the same region more than once (for + * VFIO_IOMMU_MAP_DMA, -EEXIST will trigger), or, + * + * (2) Trying to UNMAP a range that is still partially mapped. + * + * That accuracy is not required for UNMAP-only notifiers, but it is a + * must-to-have for notifiers registered with MAP events, because the + * vIOMMU needs to make sure the shadow page table is always in sync + * with the guest IOMMU pgtables for a device. + */ + IOVATree *iova_tree; }; struct VTDIOTLBEntry { From eac7a7791bb6d719233deed750034042318ffd56 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 30 Dec 2022 23:07:25 +0100 Subject: [PATCH 267/814] x86: don't let decompressed kernel image clobber setup_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setup_data links are appended to the compressed kernel image. Since the kernel image is typically loaded at 0x100000, setup_data lives at `0x100000 + compressed_size`, which does not get relocated during the kernel's boot process. The kernel typically decompresses the image starting at address 0x1000000 (note: there's one more zero there than the compressed image above). This usually is fine for most kernels. However, if the compressed image is actually quite large, then setup_data will live at a `0x100000 + compressed_size` that extends into the decompressed zone at 0x1000000. In other words, if compressed_size is larger than `0x1000000 - 0x100000`, then the decompression step will clobber setup_data, resulting in crashes. Visually, what happens now is that QEMU appends setup_data to the kernel image: kernel image setup_data |--------------------------||----------------| 0x100000 0x100000+l1 0x100000+l1+l2 The problem is that this decompresses to 0x1000000 (one more zero). So if l1 is > (0x1000000-0x100000), then this winds up looking like: kernel image setup_data |--------------------------||----------------| 0x100000 0x100000+l1 0x100000+l1+l2 d e c o m p r e s s e d k e r n e l |-------------------------------------------------------------| 0x1000000 0x1000000+l3 The decompressed kernel seemingly overwriting the compressed kernel image isn't a problem, because that gets relocated to a higher address early on in the boot process, at the end of startup_64. setup_data, however, stays in the same place, since those links are self referential and nothing fixes them up. So the decompressed kernel clobbers it. Fix this by appending setup_data to the cmdline blob rather than the kernel image blob, which remains at a lower address that won't get clobbered. This could have been done by overwriting the initrd blob instead, but that poses big difficulties, such as no longer being able to use memory mapped files for initrd, hurting performance, and, more importantly, the initrd address calculation is hard coded in qboot, and it always grows down rather than up, which means lots of brittle semantics would have to be changed around, incurring more complexity. In contrast, using cmdline is simple and doesn't interfere with anything. The microvm machine has a gross hack where it fiddles with fw_cfg data after the fact. So this hack is updated to account for this appending, by reserving some bytes. Fixup-by: Michael S. Tsirkin Cc: x86@kernel.org Cc: Philippe Mathieu-Daudé Cc: H. Peter Anvin Cc: Borislav Petkov Cc: Eric Biggers Signed-off-by: Jason A. Donenfeld Message-Id: <20221230220725.618763-1-Jason@zx2c4.com> Message-ID: <20230128061015-mutt-send-email-mst@kernel.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Eric Biggers Tested-by: Mathias Krause --- hw/i386/microvm.c | 15 +++++++---- hw/i386/x86.c | 52 +++++++++++++++++++++------------------ hw/nvram/fw_cfg.c | 9 +++++++ include/hw/i386/microvm.h | 5 ++-- include/hw/nvram/fw_cfg.h | 9 +++++++ 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 170a331e3f..29f30dd6d3 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -378,7 +378,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) MicrovmMachineState *mms = MICROVM_MACHINE(machine); BusState *bus; BusChild *kid; - char *cmdline; + char *cmdline, *existing_cmdline; + size_t len; /* * Find MMIO transports with attached devices, and add them to the kernel @@ -387,7 +388,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) * Yes, this is a hack, but one that heavily improves the UX without * introducing any significant issues. */ - cmdline = g_strdup(machine->kernel_cmdline); + existing_cmdline = fw_cfg_read_bytes_ptr(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA); + cmdline = g_strdup(existing_cmdline); bus = sysbus_get_default(); QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; @@ -411,9 +413,12 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) } } - fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1); - fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline); - + len = strlen(cmdline); + if (len > VIRTIO_CMDLINE_TOTAL_MAX_LEN + strlen(existing_cmdline)) { + fprintf(stderr, "qemu: virtio mmio cmdline too large, skipping\n"); + } else { + memcpy(existing_cmdline, cmdline, len + 1); + } g_free(cmdline); } diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 78cc131926..eaff4227bd 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -50,6 +50,7 @@ #include "hw/intc/i8259.h" #include "hw/rtc/mc146818rtc.h" #include "target/i386/sev.h" +#include "hw/i386/microvm.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/irq.h" @@ -813,12 +814,18 @@ void x86_load_linux(X86MachineState *x86ms, const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; const char *dtb_filename = machine->dtb; - const char *kernel_cmdline = machine->kernel_cmdline; + char *kernel_cmdline; SevKernelLoaderContext sev_load_ctx = {}; enum { RNG_SEED_LENGTH = 32 }; - /* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; + /* + * Add the NUL terminator, some padding for the microvm cmdline fiddling + * hack, and then align to 16 bytes as a paranoia measure + */ + cmdline_size = (strlen(machine->kernel_cmdline) + 1 + + VIRTIO_CMDLINE_TOTAL_MAX_LEN + 16) & ~15; + /* Make a copy, since we might append arbitrary bytes to it later. */ + kernel_cmdline = g_strndup(machine->kernel_cmdline, cmdline_size); /* load the kernel header */ f = fopen(kernel_filename, "rb"); @@ -959,12 +966,6 @@ void x86_load_linux(X86MachineState *x86ms, initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; } - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - sev_load_ctx.cmdline_data = (char *)kernel_cmdline; - sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; - if (protocol >= 0x202) { stl_p(header + 0x228, cmdline_addr); } else { @@ -1091,27 +1092,24 @@ void x86_load_linux(X86MachineState *x86ms, exit(1); } - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size; - kernel = g_realloc(kernel, kernel_size); - - - setup_data = (SetupData *)(kernel + setup_data_offset); + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + dtb_size; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_DTB); setup_data->len = cpu_to_le32(dtb_size); - load_image_size(dtb_filename, setup_data->data, dtb_size); } - if (!legacy_no_rng_seed) { - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH; - kernel = g_realloc(kernel, kernel_size); - setup_data = (SetupData *)(kernel + setup_data_offset); + if (!legacy_no_rng_seed && protocol >= 0x209) { + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_RNG_SEED); setup_data->len = cpu_to_le32(RNG_SEED_LENGTH); qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH); @@ -1122,6 +1120,12 @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); } + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, cmdline_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline, cmdline_size); + sev_load_ctx.cmdline_data = (char *)kernel_cmdline; + sev_load_ctx.cmdline_size = cmdline_size; + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); sev_load_ctx.kernel_data = (char *)kernel; @@ -1134,7 +1138,7 @@ void x86_load_linux(X86MachineState *x86ms, * kernel on the other side of the fw_cfg interface matches the hash of the * file the user passed in. */ - if (!sev_enabled()) { + if (!sev_enabled() && first_setup_data) { SetupDataFixup *fixup = g_malloc(sizeof(*fixup)); memcpy(setup, header, MIN(sizeof(header), setup_size)); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index a00881bc64..432754eda4 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -741,6 +741,15 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true); } +void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key) +{ + int arch = !!(key & FW_CFG_ARCH_LOCAL); + + key &= FW_CFG_ENTRY_MASK; + assert(key < fw_cfg_max_entry(s)); + return s->entries[arch][key].data; +} + void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) { size_t sz = strlen(value) + 1; diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index fad97a891d..e8af61f194 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -50,8 +50,9 @@ */ /* Platform virtio definitions */ -#define VIRTIO_MMIO_BASE 0xfeb00000 -#define VIRTIO_CMDLINE_MAXLEN 64 +#define VIRTIO_MMIO_BASE 0xfeb00000 +#define VIRTIO_CMDLINE_MAXLEN 64 +#define VIRTIO_CMDLINE_TOTAL_MAX_LEN ((VIRTIO_CMDLINE_MAXLEN + 1) * 16) #define GED_MMIO_BASE 0xfea00000 #define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100) diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 2e503904dc..990dcdbb2e 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -139,6 +139,15 @@ void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, void *data, size_t len, bool read_only); +/** + * fw_cfg_read_bytes_ptr: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * + * Reads an existing fw_cfg data pointer. + */ +void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key); + /** * fw_cfg_add_string: * @s: fw_cfg device being modified From 0711c2849735eb77b5082803c05cbaed99ccd852 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:33 +0100 Subject: [PATCH 268/814] tests: qtest: print device_add error before failing test Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-2-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/libqtest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 6b2216cb20..d658222a19 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1435,6 +1435,10 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv, resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args); g_assert(resp); g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */ + if (qdict_haskey(resp, "error")) { + fprintf(stderr, "error: %s\n", + qdict_get_str(qdict_get_qdict(resp, "error"), "desc")); + } g_assert(!qdict_haskey(resp, "error")); qobject_unref(resp); } From 36773faeebbc965e6063802ae3c215f1a5f01bda Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:34 +0100 Subject: [PATCH 269/814] tests: acpi: cleanup arguments to make them more readable no functional change Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-3-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 8608408213..08b8aee76b 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -951,8 +951,7 @@ static void test_acpi_q35_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1", - &data); + test_acpi_one("-device pci-bridge,chassis_nr=1", &data); free_test_data(&data); } @@ -962,14 +961,12 @@ static void test_acpi_q35_multif_bridge(void) .machine = MACHINE_Q35, .variant = ".multi-bridge", }; - test_acpi_one("-device pcie-root-port,id=pcie-root-port-0," - "multifunction=on," - "port=0x0,chassis=1,addr=0x2,bus=pcie.0 " - "-device pcie-root-port,id=pcie-root-port-1," - "port=0x1,chassis=2,addr=0x3.0x1,bus=pcie.0 " - "-device virtio-balloon,id=balloon0," - "bus=pcie.0,addr=0x4.0x2", - &data); + test_acpi_one( + " -device virtio-balloon,id=balloon0,addr=0x4.0x2" + " -device pcie-root-port,id=rp0,multifunction=on," + "port=0x0,chassis=1,addr=0x2" + " -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1", + &data); free_test_data(&data); } From 89b36fd8614a7d02e15a72c6aa25a3682fc7fcef Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:35 +0100 Subject: [PATCH 270/814] tests: acpi: whitelist DSDT blobs for tests that use pci-bridges Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-4-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..2602a57c9b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/DSDT.multi-bridge", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.roothp", +"tests/data/acpi/pc/DSDT.hpbridge", From 9ebb74d61486abdc1183aeb2852ffe0587d35fea Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:36 +0100 Subject: [PATCH 271/814] tests: acpi: extend pcihp with nested bridges add nested bridges/root-ports to pcihp tests, to make sure follow up patches don't break nested enumeration of bridges in DSDT. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-5-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 08b8aee76b..6a99b10384 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -863,7 +863,8 @@ static void test_acpi_piix4_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1", &data); + test_acpi_one("-device pci-bridge,chassis_nr=1 " + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); free_test_data(&data); } @@ -877,7 +878,8 @@ static void test_acpi_piix4_no_root_hotplug(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); free_test_data(&data); } @@ -891,7 +893,8 @@ static void test_acpi_piix4_no_bridge_hotplug(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); free_test_data(&data); } @@ -965,8 +968,14 @@ static void test_acpi_q35_multif_bridge(void) " -device virtio-balloon,id=balloon0,addr=0x4.0x2" " -device pcie-root-port,id=rp0,multifunction=on," "port=0x0,chassis=1,addr=0x2" - " -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1", + " -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1" + " -device pcie-root-port,id=rp2,port=0x0,chassis=3,bus=rp1,addr=0.0" + " -device pci-bridge,bus=rp2,chassis_nr=4,id=br1" + " -device pcie-root-port,id=rphptgt1,port=0x0,chassis=5,addr=2.1" + " -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2" + " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3", &data); + free_test_data(&data); } From 48dde093d30dc6d09e832e478cb6661cf633a882 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:37 +0100 Subject: [PATCH 272/814] tests: acpi: update expected blobs add extra nested bridges/root ports to blobs so it would be posible to check how follow up patches would affect it. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-6-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/pc/DSDT.bridge | Bin 9532 -> 12608 bytes tests/data/acpi/pc/DSDT.roothp | Bin 6656 -> 9732 bytes tests/data/acpi/q35/DSDT.multi-bridge | Bin 8630 -> 12301 bytes tests/qtest/bios-tables-test-allowed-diff.h | 4 ---- 4 files changed, 4 deletions(-) diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index 75016fd4b72aae544658e51c06a2940da31c81da..d1b019754bb03fa7d815ab57304ddb2376a4c8af 100644 GIT binary patch delta 153 zcmdnvbs&k$CD$rprJH)ru3^cR4nzD~mD#0L(Zn ArT_o{ delta 67 zcmV-J0KEUeV!TQUL{mgmJS6}C0c5cXcMA-QmjPT~Q$k-5f|miajSFi60z$=;`wfP( Z2@k6a2p>>GPE-JJ0h8Y_7qd<#@(RdT6?p&v diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index 545512adfa0f9af81a7fafd353679f64f75e501e..14473ab4c91d68af88fff45e703f572c387d0af7 100644 GIT binary patch delta 137 zcmZoLY4PE533dr#QDb0W{I-#+oSUb431duruv5H1*J8%a-Q3?9nfsdGC3Zd z{G8XA)hXE3hjH@^-v8VZj81-`zAj;YApy>wp^Q+53m5ZdBfff0K}T7T2-5=Y>I_DP jwqOH;&F94rGBRpTo+v5D6{i<$U=bhS>=!b5y<{K&C!r|o delta 55 zcmZqiX)xh(33dr#kYZq9WZ%eD&dufjI3_;WDPF++@#bFc?~F{ohbFi4CT`B>+r&M2 LqN>E?&8mR_$Sx8n diff --git a/tests/data/acpi/q35/DSDT.multi-bridge b/tests/data/acpi/q35/DSDT.multi-bridge index 3dba4d84369f1f2850fbdc771072519d34f58072..f045438b4e794406316418074c6d319261bfcd9e 100644 GIT binary patch delta 2396 zcmZ|R&2rLU6b9fV1R4UAzqCLp368Fuu|nw&UD+1sqAFH{Zt66SE8MwtSb!{WTy({_ z?=3jacm?jc|p2))*Ftr_b@&8YT?Q@uhip} z#y=|!SlLK#^D1Nc+r7+mcuHu-@`LxOKKSLg590SpaAV?pe)@Cy$9-srAHY1HKl_1W zDjbv0^0<0Fe`@-zE?YP!%{ua54)x`=d-s9vl!C!&OF!!kPSFIAz?+!2P7i@?pxCkv zC6NyJd?85?NvO!Se2FF#lZdG#(voD7B$8B-j$C zC6SgilQfaEitI{@&BP{RD~YsZm}H1#RAf(DvP`l>vPvQ?IVL$GIThKLmQ^OJL{^nV zTJlWtMDi-qm6igN0+E7}NK27Pkw{TR4y2{Tq(r2oB+^o5QYKPXkt1nwm^efnC6Sgj zCTm32RODD%)|spmSyvKisW7P!si;U#TB=N{M5;<6Ej1=JA~hB1OUnk64I&##A}w_$ zbs}{Y8A!_}lT9Lmx)WnRT63On0QF0w)Y?63>*Dd!;x{7nT&O9 z;kR1ByQ}PEY#TUqc`#vsyB{SM4pCBo0k(8Xnm9zsAq=n$Q!>*QQ@?{zZZgim4Qb)S z=E)OQ?Zg>&!IsAvmhHwFw!ucl8P@H^8TP^U!Wk6$`^c<87UomBXPJNNma#l)lai!J==@zCu& gfw?XDw`=c0zt;^l9Bp?(g|D{bSMBiC^6j0`U&gLNmH+?% delta 97 zcmeB8*yhaT66_MPO_70t@xex}Mma8Ty_oo5r+5Kpy~)$%?8RI-gAEPhIpQ5%f_NAh wm>4*mf?a(WC%=`8pIoh=%54diVq{>Ryjr1sv!z}PBb!u!vtJ0q Date: Thu, 12 Jan 2023 15:02:38 +0100 Subject: [PATCH 273/814] tests: acpi: cleanup use_uefi argument usage 'use_uefi' is used for the flag is a part of 'test_data *data' argument that is passed to the same functions, which makes use_uefi argument redundant. Drop it and use 'data::uefi_*' directly, instead. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-7-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 35 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 6a99b10384..cb95f687fe 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -748,9 +748,9 @@ static void test_smbios_structs(test_data *data, SmbiosEntryPointType ep_type) } } -static void test_acpi_load_tables(test_data *data, bool use_uefi) +static void test_acpi_load_tables(test_data *data) { - if (use_uefi) { + if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */ g_assert(data->scan_len); data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts, data->ram_start, data->scan_len); @@ -766,12 +766,11 @@ static void test_acpi_load_tables(test_data *data, bool use_uefi) test_acpi_fadt_table(data); } -static char *test_acpi_create_args(test_data *data, const char *params, - bool use_uefi) +static char *test_acpi_create_args(test_data *data, const char *params) { char *args; - if (use_uefi) { + if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */ /* * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3) * when arm/virt boad starts to support it. @@ -809,11 +808,10 @@ static char *test_acpi_create_args(test_data *data, const char *params, static void test_acpi_one(const char *params, test_data *data) { char *args; - bool use_uefi = data->uefi_fl1 && data->uefi_fl2; - args = test_acpi_create_args(data, params, use_uefi); + args = test_acpi_create_args(data, params); data->qts = qtest_init(args); - test_acpi_load_tables(data, use_uefi); + test_acpi_load_tables(data); if (getenv(ACPI_REBUILD_EXPECTED_AML)) { dump_aml_files(data, true); @@ -826,7 +824,7 @@ static void test_acpi_one(const char *params, test_data *data) * Bug on uefi-test-tools to provide entry point: * https://bugs.launchpad.net/qemu/+bug/1821884 */ - if (!use_uefi) { + if (!(data->uefi_fl1 && data->uefi_fl2)) { SmbiosEntryPointType ep_type = test_smbios_entry_point(data); test_smbios_structs(data, ep_type); } @@ -1904,10 +1902,9 @@ static void test_acpi_piix4_oem_fields(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - args = test_acpi_create_args(&data, - OEM_TEST_ARGS, false); + args = test_acpi_create_args(&data, OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1924,10 +1921,9 @@ static void test_acpi_q35_oem_fields(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - args = test_acpi_create_args(&data, - OEM_TEST_ARGS, false); + args = test_acpi_create_args(&data, OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1942,9 +1938,9 @@ static void test_acpi_microvm_oem_fields(void) test_acpi_microvm_prepare(&data); args = test_acpi_create_args(&data, - OEM_TEST_ARGS",acpi=on", false); + OEM_TEST_ARGS",acpi=on"); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1964,10 +1960,9 @@ static void test_acpi_virt_oem_fields(void) }; char *args; - args = test_acpi_create_args(&data, - "-cpu cortex-a57 "OEM_TEST_ARGS, true); + args = test_acpi_create_args(&data, "-cpu cortex-a57 "OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, true); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); From 025cfbbac81d350d58599f4f2d00c51770068058 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:39 +0100 Subject: [PATCH 274/814] pci_bridge: remove whitespace Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-8-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_bridge_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 3435df8d73..4b2696ea7f 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -186,7 +186,6 @@ static Property pci_bridge_dev_properties[] = { res_reserve.mem_pref_32, -1), DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev, res_reserve.mem_pref_64, -1), - DEFINE_PROP_END_OF_LIST(), }; From f7b35824b1247d1b32b0b1001ac481d6338891fa Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:40 +0100 Subject: [PATCH 275/814] x86: acpi: pcihp: clean up duplicate bridge_in_acpi assignment Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-9-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8c333973f9..8ba34d8fde 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -464,7 +464,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, call_dev_aml_func(DEVICE(pdev), dev); - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; if (bridge_in_acpi) { /* * device is coldplugged bridge, From 1d77e15718c83b84aa46cfb12493a1dafa2a3252 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:41 +0100 Subject: [PATCH 276/814] pci: acpi hotplug: rename x-native-hotplug to x-do-not-expose-native-hotplug-cap When ACPI PCI hotplug for Q35 was introduced (6.1), it was implemented by hiding HPC capability on PCIE slot. That however led to a number of regressions and to fix it, it was decided to keep HPC cap exposed in ACPI PCI hotplug case and force guest in ACPI PCI hotplug mode by other means [1]. That reduced meaning of x-native-hotplug to a compat knob [2] for broken 6.1 machine type. Rename property to match its current purpose. 1) 211afe5c69 (hw/i386/acpi-build: Deny control on PCIe Native Hot-plug in _OSC) 2) c318bef762 (hw/acpi/ich9: Add compat prop to keep HPC bit set for 6.1 machine type) Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-10-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_q35.c | 5 +++-- hw/pci-bridge/gen_pcie_root_port.c | 7 ++++++- hw/pci/pcie.c | 6 +++--- hw/pci/pcie_port.c | 3 ++- include/hw/pci/pcie_port.h | 3 ++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 83c57c6eb1..66cd718b70 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -257,8 +257,9 @@ static void pc_q35_init(MachineState *machine) NULL); if (!keep_pci_slot_hpc && acpi_pcihp) { - object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug", - "false", true); + object_register_sugar_prop(TYPE_PCIE_SLOT, + "x-do-not-expose-native-hotplug-cap", + "true", true); } /* irq lines */ diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 20099a8ae3..1ce4e7beba 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -87,7 +87,12 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) return; } - if (grp->res_reserve.io == -1 && s->hotplug && !s->native_hotplug) { + /* + * reserving IO space led to worse issues in 6.1, when this hunk was + * introduced. (see commit: 211afe5c69b59). Keep this broken for 6.1 + * machine type ABI compatibility only + */ + if (s->hide_native_hotplug_cap && grp->res_reserve.io == -1 && s->hotplug) { grp->res_reserve.io = GEN_PCIE_ROOT_DEFAULT_IO_RANGE; } int rc = pci_bridge_qemu_reserve_cap_init(d, 0, diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 68a62da0b5..924fdabd15 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -611,11 +611,11 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s) PCI_EXP_SLTCAP_ABP); /* - * Enable native hot-plug on all hot-plugged bridges unless - * hot-plug is disabled on the slot. + * Expose native hot-plug on all bridges if hot-plug is enabled on the slot. + * (unless broken 6.1 ABI is enforced for compat reasons) */ if (s->hotplug && - (s->native_hotplug || DEVICE(dev)->hotplugged)) { + (!s->hide_native_hotplug_cap || DEVICE(dev)->hotplugged)) { pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, PCI_EXP_SLTCAP_HPS | PCI_EXP_SLTCAP_HPC); diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 687e4e763a..65a397ad23 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -173,7 +173,8 @@ static Property pcie_slot_props[] = { DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true), - DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true), + DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot, + hide_native_hotplug_cap, false), DEFINE_PROP_END_OF_LIST() }; diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index fd484afb30..6c40e3733f 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -63,7 +63,8 @@ struct PCIESlot { /* Indicates whether any type of hot-plug is allowed on the slot */ bool hotplug; - bool native_hotplug; + /* broken ACPI hotplug compat knob to preserve 6.1 ABI intact */ + bool hide_native_hotplug_cap; QLIST_ENTRY(PCIESlot) next; }; From 45284cfb49a47bb4536e29b4965a41a0ecb63149 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:42 +0100 Subject: [PATCH 277/814] pcihp: piix4: do not call acpi_pcihp_reset() when ACPI PCI hotplug is disabled piix4_pm_reset() is calling acpi_pcihp_reset() when ACPI PCI hotplug is disabled, which leads to assigning BSEL properties to bridges on path acpi_set_bsel() ... if (qbus_is_hotpluggable(BUS(bus))) { // above happens to be true by default (though it's SHPC hotplug handler) // set BSEL } At the moment the issue is masked by the fact that we use not only BSEL, to decide if we should generated hoplug AML but also pcihp_bridge_en knob. However the later patches will drop dependency on pcihp_bridge_en, and use only BSEL exclusively to decide if hotplug AML for slots should be built, which exposes issue. We should not ever call acpi_pcihp_reset() if ACPI PCI hotplug is disabled, make it so. PS: * Q35 does the right thing (i.e. it calls acpi_pcihp_reset only when pcihp is enabled) * the issue also makes acpi_pcihp_update() logic run on SHPC enabled bridges, which seems to be harmless Fixes: 3d7e78aa777 ("Introduce a new flag for i440fx to disable PCI hotplug on the root bus") Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-11-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/piix4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 2ab4930f11..724294b378 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -304,7 +304,9 @@ static void piix4_pm_reset(DeviceState *dev) acpi_update_sci(&s->ar, s->irq); pm_io_space_update(s); - acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug); + if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) { + acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug); + } } static void piix4_pm_powerdown_req(Notifier *n, void *opaque) From 2940a4b9e3d206cc759c7630dde2fb7ded3e9ec2 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:43 +0100 Subject: [PATCH 278/814] pci: acpihp: assign BSEL only to coldplugged bridges ACPI PCI hotplug would broken after bridge hotplug and then migration if hotplugged bridge were specified on target at command line. Currently it's not possible since, 'hotplugged' property was made read-only for some time now. The issue would happen due to BSEL being assigned to all bridges during 1st 'reset': source seq: 1. start 'pc' machine => sets BSEL to 0 on pci.0 (host-bridge) 2. hotplug bridge, no bsel is assigned (so far is ok) target seq: 1. start 'pc' machine with -S -device pci-bridge,id=hp_br,hotplugged=on BSEL gets assigned to as follows hp_br: 0 pci.0: 1 as result hotplug requests with migrated AML generated on source would be misdirected to 'hp_br' instead of intended pci.0 While it's not issue at the moment, it's based on implicit assumptions * 'hotplugged' property is read-only * 1st reset happens before QEMU drops into monitor mode which lets add hotplugged on source bridges as hotplugged ones (anything added at that stage counts as hotplugged (yet another assumption)) All of it looks too fragile to me, so lets restrict BSEL only to cold-plugged bridges explicitly. Migration wise it shouldn't break anything since assignment order stays the same: * user can't specify 'hotplugged=on' on CLI * user can't specify 'hotplugged=off' at monitor stage or later on older QEMU versions where 'hotplugged' is RW, hotplug is broken after migration anyways and we cannot do anything to fix that. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-12-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/pcihp.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 99a898d9ae..5dc7377411 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -85,31 +85,40 @@ static int acpi_pcihp_get_bsel(PCIBus *bus) } } -/* Assign BSEL property to all buses. In the future, this can be changed - * to only assign to buses that support hotplug. - */ +typedef struct { + unsigned bsel_alloc; + bool has_bridge_hotplug; +} BSELInfo; + +/* Assign BSEL property only to buses that support hotplug. */ static void *acpi_set_bsel(PCIBus *bus, void *opaque) { - unsigned *bsel_alloc = opaque; + BSELInfo *info = opaque; unsigned *bus_bsel; + DeviceState *br = bus->qbus.parent; + bool is_bridge = IS_PCI_BRIDGE(br); + /* hotplugged bridges can't be described in ACPI ignore them */ if (qbus_is_hotpluggable(BUS(bus))) { - bus_bsel = g_malloc(sizeof *bus_bsel); + if (!is_bridge || (!br->hotplugged && info->has_bridge_hotplug)) { + bus_bsel = g_malloc(sizeof *bus_bsel); - *bus_bsel = (*bsel_alloc)++; - object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, - bus_bsel, OBJ_PROP_FLAG_READ); + *bus_bsel = info->bsel_alloc++; + object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, + bus_bsel, OBJ_PROP_FLAG_READ); + } } - return bsel_alloc; + return info; } -static void acpi_set_pci_info(void) +static void acpi_set_pci_info(bool has_bridge_hotplug) { static bool bsel_is_set; Object *host = acpi_get_i386_pci_host(); PCIBus *bus; - unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT; + BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT, + .has_bridge_hotplug = has_bridge_hotplug }; if (bsel_is_set) { return; @@ -123,7 +132,7 @@ static void acpi_set_pci_info(void) bus = PCI_HOST_BRIDGE(host)->bus; if (bus) { /* Scan all PCI buses. Set property to enable acpi based hotplug. */ - pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc); + pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info); } } @@ -287,7 +296,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off) if (acpihp_root_off) { acpi_pcihp_disable_root_bus(); } - acpi_set_pci_info(); + acpi_set_pci_info(!s->legacy_piix); acpi_pcihp_update(s); } From debbda1c67eac6c4b44d07fe4301ff9b57c82afa Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:44 +0100 Subject: [PATCH 279/814] x86: pcihp: fix invalid AML PCNT calls to hotplugged bridges When QEMU is started with hotplugged bridges (think migration): QEMU -S -monitor stdio \ -device pci-bridge,chassis_nr=1 \ -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 (qemu) device_add pci-bridge,id=hpbr,bus=pci.1,addr=2.0,chassis_nr=3 (qemu) cont it will generate AML calls to hpbr's PCNT, which doesn't exists since it's hotplugged bridge. As result DSDT becomes malformed, with consequences that hotplug might stop working at best or crash guest OS at worst, when it attempts to call non existing PCNT method or during OS guest reboot when parsing DSDT again. IASL de-compiles malformed AML of above config DSDT as: + External (_SB_.PCI0.S18_.S10_.PCNT, MethodObj) // Warning: Unknown method, guessing 1 arguments + External (_SB_.PCI0.S18_.S19_.PCNT, MethodObj) // Warning: Unknown method, guessing 2 arguments ... BNUM = One DVNT (PCIU, One) DVNT (PCID, 0x03) - ^S08.PCNT () + ^S19.PCNT (^S10.PCNT (^S08.PCNT ())) } } With BSEL assignment limited only to coldplugged bridges [1], it should be possible to add PCNT call to a child bridge only if the child has BSEL property, otherwise ignore it since it's hotplugged. Which should fix the issue. 1) ("pci: acpihp: assign BSEL only to coldplugged bridges") Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-13-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8ba34d8fde..1c51ab01fc 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -515,7 +515,8 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, /* Notify about child bus events in any case */ if (pcihp_bridge_en) { QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_is_root(sec)) { + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { continue; } From 6dfcb0e797b7607d4f4ee98a7a93d01c5cb10bbc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:45 +0100 Subject: [PATCH 280/814] tests: boot_sector_test: avoid crashing if status is not available yet If test case was started in paused mode (-S CLI option) and then allowed to continue via QMP, boot_sector_test could assert on transient state with following error: assertion failed (qdict_get_try_str(qret, "status") == "running"): (NULL == "running") Instead of crashing test if 'status' is not available yet, skip check and repeat iteration again after TEST_DELAY has elapsed. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-14-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/boot-sector.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c index 44a109abd8..d3f68018e7 100644 --- a/tests/qtest/boot-sector.c +++ b/tests/qtest/boot-sector.c @@ -160,7 +160,9 @@ void boot_sector_test(QTestState *qts) qrsp = qtest_qmp(qts, "{ 'execute': 'query-status' }"); qret = qdict_get_qdict(qrsp, "return"); g_assert_nonnull(qret); - g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running"); + if (qdict_get_try_str(qret, "status")) { + g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running"); + } qobject_unref(qrsp); g_usleep(TEST_DELAY); From 2f447a36e7336129886db224661f9151f27b853c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:46 +0100 Subject: [PATCH 281/814] tests: acpi: extend bridge tests with hotplugged bridges with previous commit fixing malformed PCNT calls to hotplugged bridges, it should be possible add coldplug/hotplug test when describing PCI topology in DSDT without breeaking CI. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-15-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 48 ++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index cb95f687fe..b65e864a9c 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -805,12 +805,15 @@ static char *test_acpi_create_args(test_data *data, const char *params) return args; } -static void test_acpi_one(const char *params, test_data *data) +static void test_vm_prepare(const char *params, test_data *data) { - char *args; - - args = test_acpi_create_args(data, params); + char *args = test_acpi_create_args(data, params); data->qts = qtest_init(args); + g_free(args); +} + +static void process_acpi_tables(test_data *data) +{ test_acpi_load_tables(data); if (getenv(ACPI_REBUILD_EXPECTED_AML)) { @@ -830,7 +833,12 @@ static void test_acpi_one(const char *params, test_data *data) } qtest_quit(data->qts); - g_free(args); +} + +static void test_acpi_one(const char *params, test_data *data) +{ + test_vm_prepare(params, data); + process_acpi_tables(data); } static uint8_t base_required_struct_types[] = { @@ -861,8 +869,21 @@ static void test_acpi_piix4_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1 " - "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); + test_vm_prepare("-S" + " -device pci-bridge,chassis_nr=1" + " -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2", &data); + + /* hotplugged bridges section */ + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr", + "{'bus': 'pci.1', 'addr': '2.0', 'chassis_nr': 3 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr_multifunc", + "{'bus': 'pci.1', 'addr': '0xf.1', 'chassis_nr': 4 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbrhost", + "{'bus': 'pci.0', 'addr': '4.0', 'chassis_nr': 5 }"); + qtest_qmp_send(data.qts, "{'execute':'cont' }"); + qtest_qmp_eventwait(data.qts, "RESUME"); + + process_acpi_tables(&data); free_test_data(&data); } @@ -962,7 +983,7 @@ static void test_acpi_q35_multif_bridge(void) .machine = MACHINE_Q35, .variant = ".multi-bridge", }; - test_acpi_one( + test_vm_prepare("-S" " -device virtio-balloon,id=balloon0,addr=0x4.0x2" " -device pcie-root-port,id=rp0,multifunction=on," "port=0x0,chassis=1,addr=0x2" @@ -974,6 +995,17 @@ static void test_acpi_q35_multif_bridge(void) " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3", &data); + /* hotplugged bridges section */ + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1", + "{'bus': 'br1', 'addr': '6.0', 'chassis_nr': 128 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr2-multiif", + "{ 'bus': 'br1', 'addr': '2.2', 'chassis_nr': 129 }"); + qtest_qmp_device_add(data.qts, "pcie-pci-bridge", "hpbr3", + "{'bus': 'rp0', 'addr': '0.0' }"); + qtest_qmp_send(data.qts, "{'execute':'cont' }"); + qtest_qmp_eventwait(data.qts, "RESUME"); + + process_acpi_tables(&data); free_test_data(&data); } From 2efe88a94863d5ca6ec04126b9090c2c2cd64f97 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:47 +0100 Subject: [PATCH 282/814] tests: boot_sector_test(): make it multi-shot if the function is called the 2nd time within the same qtest session, it will prematurely return before boot sector is executed due to remaining signature. Follow up patch will add VM reboot to a test case and will call boot_sector_test() again within the same qtest env, which may lead to above issue. To fix it make sure signature in VM RAM is no more before exiting boot_sector_test(), so next time it's called it will wait boot sector is completed again. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-16-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/boot-sector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c index d3f68018e7..679ee17e2a 100644 --- a/tests/qtest/boot-sector.c +++ b/tests/qtest/boot-sector.c @@ -153,6 +153,8 @@ void boot_sector_test(QTestState *qts) signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1); signature = (signature_high << 8) | signature_low; if (signature == SIGNATURE) { + /* wipe signature */ + qtest_writeb(qts, SIGNATURE_ADDR, 0x00); break; } From c0d19126f39000181a007371b9200fd2e2b0dcc8 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:48 +0100 Subject: [PATCH 283/814] tests: acpi: add reboot cycle to bridge test hotplugged bridges should not be described in DSDT, while it works on cold boot, some ACPPI PCI code are invoked during reboot. This patch will let us catch unexpected AML if hotplug checks are broken. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-17-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index b65e864a9c..a8c17461c8 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -812,7 +812,7 @@ static void test_vm_prepare(const char *params, test_data *data) g_free(args); } -static void process_acpi_tables(test_data *data) +static void process_acpi_tables_noexit(test_data *data) { test_acpi_load_tables(data); @@ -831,7 +831,11 @@ static void process_acpi_tables(test_data *data) SmbiosEntryPointType ep_type = test_smbios_entry_point(data); test_smbios_structs(data, ep_type); } +} +static void process_acpi_tables(test_data *data) +{ + process_acpi_tables_noexit(data); qtest_quit(data->qts); } @@ -883,6 +887,11 @@ static void test_acpi_piix4_tcg_bridge(void) qtest_qmp_send(data.qts, "{'execute':'cont' }"); qtest_qmp_eventwait(data.qts, "RESUME"); + process_acpi_tables_noexit(&data); + free_test_data(&data); + + /* check that reboot/reset doesn't change any ACPI tables */ + qtest_qmp_send(data.qts, "{'execute':'system_reset' }"); process_acpi_tables(&data); free_test_data(&data); } @@ -1005,6 +1014,11 @@ static void test_acpi_q35_multif_bridge(void) qtest_qmp_send(data.qts, "{'execute':'cont' }"); qtest_qmp_eventwait(data.qts, "RESUME"); + process_acpi_tables_noexit(&data); + free_test_data(&data); + + /* check that reboot/reset doesn't change any ACPI tables */ + qtest_qmp_send(data.qts, "{'execute':'system_reset' }"); process_acpi_tables(&data); free_test_data(&data); } From 54836748fc32ea4c564585fad58a2a7e1fdae522 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:49 +0100 Subject: [PATCH 284/814] tests: acpi: whitelist DSDT before refactoring acpi based PCI hotplug machinery Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-18-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..dea61d94f1 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,2 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.hpbrroot", From 19f5052cebe46a6faef3e0065e40a622a8798473 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:50 +0100 Subject: [PATCH 285/814] pcihp: drop pcihp_bridge_en dependency when composing PCNT method .. and use only BSEL presence to decide on how PCNT should be composed. That simplifies possible combinations to consider, but mainly it makes PCIHP AML be governed only by BSEL, which is property of PCIBus (aka part of bridge) and as result it opens possibility to convert build_append_pci_bus_devices() into AcpiDevAmlIf::build_dev_aml callback to make bridges self describing. PS: used approach leaves unused PCNT, when ACPI hotplug is completely disabled but that's harmless and followup commits will get rid of it later. Scope (PCI0) ... Method (PCNT, 0, NotSerialized) { } ... } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-19-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 53 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 1c51ab01fc..27f2cc4180 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -494,39 +494,34 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, aml_append(parent_scope, notify_method); } - /* Append PCNT method to notify about events on local and child buses. - * Add this method for root bus only when hotplug is enabled since DSDT - * expects it. + /* + * Append PCNT method to notify about events on local and child buses. */ - if (bsel || pcihp_bridge_en) { - method = aml_method("PCNT", 0, AML_NOTSERIALIZED); + method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - /* If bus supports hotplug select it and notify about local events */ - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + /* If bus supports hotplug select it and notify about local events */ + if (bsel) { + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); - aml_append(method, aml_call2("DVNT", aml_name("PCIU"), - aml_int(1))); /* Device Check */ - aml_append(method, aml_call2("DVNT", aml_name("PCID"), - aml_int(3))); /* Eject Request */ - } - - /* Notify about child bus events in any case */ - if (pcihp_bridge_en) { - QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_is_root(sec) || - !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { - continue; - } - - aml_append(method, aml_name("^S%.02X.PCNT", - sec->parent_dev->devfn)); - } - } - - aml_append(parent_scope, method); + aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); + aml_append(method, aml_call2("DVNT", aml_name("PCIU"), + aml_int(1))); /* Device Check */ + aml_append(method, aml_call2("DVNT", aml_name("PCID"), + aml_int(3))); /* Eject Request */ } + + /* Notify about child bus events in any case */ + QLIST_FOREACH(sec, &bus->child, sibling) { + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; + } + + aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn)); + } + + aml_append(parent_scope, method); + qobject_unref(bsel); } From 54f82b6461703611b0a0a08c98a25ba226f6a07a Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:51 +0100 Subject: [PATCH 286/814] tests: acpi: update expected blobs expected change: Scope (PCI0) ... Method (PCNT, 0, NotSerialized) { } ... } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-20-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT.hpbrroot | Bin 3064 -> 3071 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot index 578468f4f00a9373366c92926b512c192dd6675b..42d923ef3fcc17898955ff30a1dda1bfd7da0947 100644 GIT binary patch delta 42 ycmew%{$HHSCD Date: Thu, 12 Jan 2023 15:02:52 +0100 Subject: [PATCH 287/814] tests: acpi: whitelist DSDT before refactoring acpi based PCI hotplug machinery Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-21-imammedo@redhat.com> --- tests/qtest/bios-tables-test-allowed-diff.h | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..4be20b2cd1 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,37 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.numamem", +"tests/data/acpi/pc/DSDT.nohpet", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/DSDT.roothp", +"tests/data/acpi/pc/DSDT.hpbrroot", +"tests/data/acpi/pc/DSDT.hpbridge", +"tests/data/acpi/q35/DSDT", +"tests/data/acpi/q35/DSDT.tis.tpm2", +"tests/data/acpi/q35/DSDT.tis.tpm12", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.multi-bridge", +"tests/data/acpi/q35/DSDT.mmio64", +"tests/data/acpi/q35/DSDT.ipmibt", +"tests/data/acpi/q35/DSDT.cphp", +"tests/data/acpi/q35/DSDT.memhp", +"tests/data/acpi/q35/DSDT.numamem", +"tests/data/acpi/q35/DSDT.nohpet", +"tests/data/acpi/q35/DSDT.dimmpxm", +"tests/data/acpi/q35/DSDT.acpihmat", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/DSDT.applesmc", +"tests/data/acpi/q35/DSDT.pvpanic-isa", +"tests/data/acpi/q35/DSDT.ivrs", +"tests/data/acpi/q35/DSDT.viot", +"tests/data/acpi/q35/DSDT.cxl", +"tests/data/acpi/q35/DSDT.ipmismbus", +"tests/data/acpi/q35/DSDT.xapic", +"tests/data/acpi/q35/DSDT.acpihmat-noinitiator", +"tests/data/acpi/q35/DSDT.core-count2", From ddab4d3fae4e8cb3b1d70c9f2364987ddc18c6a3 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:53 +0100 Subject: [PATCH 288/814] pcihp: compose PCNT callchain right before its user _GPE._E01 it's a stepping stone to making build_append_pci_bus_devices() suitable for AcpiDevAmlIfClass:build_dev_aml callback and lets further simplify it by separating PCNT generation from slots descriptions. It also makes PCNT callchain ASL much more readable since callchain not longer cluttered by slots descriptors. Plus, move will let next patch easily drop empty PCNT (pc/q35) when there is nothing hotpluggable. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-22-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 27f2cc4180..d434ad9189 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -388,7 +388,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, { Aml *dev, *notify_method = NULL, *method; QObject *bsel; - PCIBus *sec; int devfn; bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); @@ -494,12 +493,35 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, aml_append(parent_scope, notify_method); } + qobject_unref(bsel); +} + +static void build_append_notfication_callback(Aml *parent_scope, + const PCIBus *bus) +{ + Aml *method; + PCIBus *sec; + QObject *bsel; + + QLIST_FOREACH(sec, &bus->child, sibling) { + Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; + } + build_append_notfication_callback(br_scope, sec); + aml_append(parent_scope, br_scope); + } + /* * Append PCNT method to notify about events on local and child buses. + * ps: hostbridge might not have hotplug (bsel) enabled but might have + * child bridges that do have bsel. */ method = aml_method("PCNT", 0, AML_NOTSERIALIZED); /* If bus supports hotplug select it and notify about local events */ + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); if (bsel) { uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); @@ -521,7 +543,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, } aml_append(parent_scope, method); - qobject_unref(bsel); } @@ -1721,6 +1742,13 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { + Object *pci_host = acpi_get_i386_pci_host(); + PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; + + scope = aml_scope("\\_SB.PCI0"); + build_append_notfication_callback(scope, bus); + aml_append(dsdt, scope); + scope = aml_scope("_GPE"); { method = aml_method("_E01", 0, AML_NOTSERIALIZED); From 219e638f3b3f3e34b5cf00c0a0d536a7e0155f70 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:54 +0100 Subject: [PATCH 289/814] pcihp: do not put empty PCNT in DSDT count number of PCNT methods that actually call Notify and if there aren't any, drop PCNT altogether. It mostly affects 'Q35' tests where there is no root-ports /bridges attached and 'PC' machine when ACPI PCI hotplug is completely disabled. Expected ASL change: - Method (PCNT, 0, NotSerialized) - { - } ... Method (_E01, 0, NotSerialized) // _Exx: Edge-Triggered GPE { - Acquire (\_SB.PCI0.BLCK, 0xFFFF) - \_SB.PCI0.PCNT () - Release (\_SB.PCI0.BLCK) } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-23-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d434ad9189..6368fcefa3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -496,12 +496,13 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, qobject_unref(bsel); } -static void build_append_notfication_callback(Aml *parent_scope, +static bool build_append_notfication_callback(Aml *parent_scope, const PCIBus *bus) { Aml *method; PCIBus *sec; QObject *bsel; + int nr_notifiers = 0; QLIST_FOREACH(sec, &bus->child, sibling) { Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); @@ -509,7 +510,8 @@ static void build_append_notfication_callback(Aml *parent_scope, !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { continue; } - build_append_notfication_callback(br_scope, sec); + nr_notifiers = nr_notifiers + + build_append_notfication_callback(br_scope, sec); aml_append(parent_scope, br_scope); } @@ -530,6 +532,7 @@ static void build_append_notfication_callback(Aml *parent_scope, aml_int(1))); /* Device Check */ aml_append(method, aml_call2("DVNT", aml_name("PCID"), aml_int(3))); /* Eject Request */ + nr_notifiers++; } /* Notify about child bus events in any case */ @@ -544,6 +547,7 @@ static void build_append_notfication_callback(Aml *parent_scope, aml_append(parent_scope, method); qobject_unref(bsel); + return !!nr_notifiers; } static Aml *aml_pci_pdsm(void) @@ -1742,20 +1746,26 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { + bool has_pcnt; + Object *pci_host = acpi_get_i386_pci_host(); PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; scope = aml_scope("\\_SB.PCI0"); - build_append_notfication_callback(scope, bus); - aml_append(dsdt, scope); + has_pcnt = build_append_notfication_callback(scope, bus); + if (has_pcnt) { + aml_append(dsdt, scope); + } scope = aml_scope("_GPE"); { method = aml_method("_E01", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); - aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); - aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + if (has_pcnt) { + aml_append(method, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + } aml_append(scope, method); } aml_append(dsdt, scope); From 15dcfb197ee6c2c84a0a3d1a926bec81203e42dc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:55 +0100 Subject: [PATCH 290/814] tests: acpi: update expected blobs Expected changes: * pc/bridge testcase due to ("pcihp: compose PCNT callchain right before its user _GPE._E01") ... + Scope (\_SB.PCI0) + { + Scope (S18) + { + Scope (S08) + { + Method (PCNT, 0, NotSerialized) + { + BNUM = 0x02 + DVNT (PCIU, One) + DVNT (PCID, 0x03) + } + } Method (PCNT, 0, NotSerialized) { - BNUM = Zero + BNUM = One DVNT (PCIU, One) DVNT (PCID, 0x03) - ^S18.PCNT () + ^S08.PCNT () } } + + Method (PCNT, 0, NotSerialized) + { + BNUM = Zero + DVNT (PCIU, One) + DVNT (PCID, 0x03) + ^S18.PCNT () + } } Scope (_GPE) * due to ("pcihp: do not put empty PCNT in DSDT") in the most Q35 tests ... { Name (_ADR, 0x001F0003) // _ADR: Address } - - Method (PCNT, 0, NotSerialized) - { - } } } ... { Method (_E01, 0, NotSerialized) // _Exx: Edge-Triggered GPE { - Acquire (\_SB.PCI0.BLCK, 0xFFFF) - \_SB.PCI0.PCNT () - Release (\_SB.PCI0.BLCK) } } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-24-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT | Bin 6458 -> 6470 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 6418 -> 6430 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 7783 -> 7795 bytes tests/data/acpi/pc/DSDT.bridge | Bin 12608 -> 12634 bytes tests/data/acpi/pc/DSDT.cphp | Bin 6922 -> 6934 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 8112 -> 8124 bytes tests/data/acpi/pc/DSDT.hpbridge | Bin 6418 -> 6430 bytes tests/data/acpi/pc/DSDT.hpbrroot | Bin 3071 -> 3064 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 6530 -> 6542 bytes tests/data/acpi/pc/DSDT.memhp | Bin 7817 -> 7829 bytes tests/data/acpi/pc/DSDT.nohpet | Bin 6316 -> 6328 bytes tests/data/acpi/pc/DSDT.numamem | Bin 6464 -> 6476 bytes tests/data/acpi/pc/DSDT.roothp | Bin 9732 -> 9758 bytes tests/data/acpi/q35/DSDT | Bin 8310 -> 8252 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 8327 -> 8269 bytes tests/data/acpi/q35/DSDT.acpihmat | Bin 9635 -> 9577 bytes tests/data/acpi/q35/DSDT.acpihmat-noinitiator | Bin 8589 -> 8531 bytes tests/data/acpi/q35/DSDT.applesmc | Bin 8356 -> 8298 bytes tests/data/acpi/q35/DSDT.bridge | Bin 11439 -> 11458 bytes tests/data/acpi/q35/DSDT.core-count2 | Bin 32450 -> 32392 bytes tests/data/acpi/q35/DSDT.cphp | Bin 8774 -> 8716 bytes tests/data/acpi/q35/DSDT.cxl | Bin 9636 -> 9578 bytes tests/data/acpi/q35/DSDT.dimmpxm | Bin 9964 -> 9906 bytes tests/data/acpi/q35/DSDT.ipmibt | Bin 8385 -> 8327 bytes tests/data/acpi/q35/DSDT.ipmismbus | Bin 8398 -> 8340 bytes tests/data/acpi/q35/DSDT.ivrs | Bin 8327 -> 8269 bytes tests/data/acpi/q35/DSDT.memhp | Bin 9669 -> 9611 bytes tests/data/acpi/q35/DSDT.mmio64 | Bin 9440 -> 9382 bytes tests/data/acpi/q35/DSDT.multi-bridge | Bin 12301 -> 12358 bytes tests/data/acpi/q35/DSDT.nohpet | Bin 8168 -> 8110 bytes tests/data/acpi/q35/DSDT.numamem | Bin 8316 -> 8258 bytes tests/data/acpi/q35/DSDT.pvpanic-isa | Bin 8411 -> 8353 bytes tests/data/acpi/q35/DSDT.tis.tpm12 | Bin 8916 -> 8858 bytes tests/data/acpi/q35/DSDT.tis.tpm2 | Bin 8942 -> 8884 bytes tests/data/acpi/q35/DSDT.viot | Bin 9419 -> 9361 bytes tests/data/acpi/q35/DSDT.xapic | Bin 35673 -> 35615 bytes tests/qtest/bios-tables-test-allowed-diff.h | 36 ------------------ 37 files changed, 36 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index b688686dc3614f56582991c0974f6ef1964ee6ce..c99179b35254725daeebb416400b1b6f9f1d74c4 100644 GIT binary patch delta 51 zcmdmGbj*m$CDWCDp4a&GRf0H&DuV5fM2#(>Q|+&N54-3^m}@wPKL9iDuK z+i3GvzJJ`C!}#ktHwUX+WZdkh*1@GB;Kvc82htPZ>}eq2&KhiJ5ig(?Y+w;Dq7dNh f7s61$#WeZ8fjFm#CWOlfG9=Lflg2PAv-l6)2(#cWs{xbnFltGUA!z^r diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index 53eb0dd7d422e880a668cf3ea01b8b288004042a..659ad3d6b9026c090e0d8d8e21ece5df44249ec0 100644 GIT binary patch delta 51 zcmeA&n`Xx466_KpCe6UWxPBv-2QTNT(W8#CI;sqS9Ze|qn=j9R5j?n`N1UP#dOb(Dw F005}751ar1 delta 38 ucmdmEzrmi%CDsxPLG*^*2p!<4tBfI=PU~ zc(W|uA8rK^`2c6X5QYLqC%;f%moUGO0B6roMkvFDi+S@NzIx8hGn6kfPF}294FFm9 BAYA|e diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 2771bcea89b531549557a19538606219a8e222b1..d68c472b460e4609a64ea67de3c4cebfca76164d 100644 GIT binary patch delta 49 zcmez7u*ZSRCDqa2sFR7`xZQ@nt))aI#jvl!h)*aDpWLKp<>(C*0P66_MvuE4;+D7ulWQI5+;Iwn5YDPF)udh=Ad)r{^UYyr-GAq)cc@$Lbx nB9`&428ImL$}#%PAXNd*o(4`n&ffq3BME@iN2?CD_ diff --git a/tests/data/acpi/q35/DSDT.core-count2 b/tests/data/acpi/q35/DSDT.core-count2 index 375aceed6b16528f7986fad46b045eba76af9760..0603db8cc63cfc562f83e55eaf5162e7c29bf4d1 100644 GIT binary patch delta 51 zcmX@~m$Bn7BbQ6COGrl@0|VoRja+AIxLl-S;)9*y1$-noKdhO>$Sc4T?;hYP!WQpp HV8{Rf*RK!t delta 109 zcmeD9%XsK7BbQ6COUR)*1_s6n8@bNbaCu9`#0NXY3ph({epoY$(OrZsz}YW^LBKxV pJ-}7OGTzm|kRe(*MxPm^D!|#(z{$ti`~QC=0g(D=btD0h3IKv5Auj*` diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index a0ecafc36c57c6d4791b511f3febe210713d253c..beeb83c33b385fc8b41d44f299b8d9ba7203d935 100644 GIT binary patch delta 49 zcmX@+(&NJA66_Mfqr||#_;VvypaPeRR7`xZQ@ntW-&MH0rDEcPo#F+Yr8aY`&SG>IVGD5f3tf66_LkP=SGgan?qzMmbJ5`Iz`%r+5Ls%~Rx_F}jPe1vvYKFbLSky9c<6 mSjM{=7&1gF$LKSI6a_eY8aVkld;kBBBmhz$t&SuBQUL&4{~kpE diff --git a/tests/data/acpi/q35/DSDT.ipmismbus b/tests/data/acpi/q35/DSDT.ipmismbus index 3f32dffdbf3cd7e3791155530cf89417d8f2ec90..6c5d1afe443d9261d3b93801711f8d5b267696f3 100644 GIT binary patch delta 48 zcmX@-IK`36CD(C*0P66_MvuE4;+D7ulWQI5+;Iwn5YDPF)udh=Ad)r{^UYyr-GAq)cc@$Lbx nB9`&428ImL$}#%PAXNd*o(4`n&ffq3BME@iN2?(3`;J66_MfYrw$3D7cZUQI5MwgfS*Q*ePD1Q+V<;IR_>;&dE3AiYKqpS7eE9 z0&@K2izolm194n9Cm)k9ntVl10m89SD4M)ZPeC@i$@N08p=CTryrWAH4%f@R`r4cAbYmGO IpVhAf00jg!7ytkO diff --git a/tests/data/acpi/q35/DSDT.nohpet b/tests/data/acpi/q35/DSDT.nohpet index b116947dacd4fe9b563ecc7e1510cdb2474011cb..9ff9983a80a7487470ccd02ce587200444675816 100644 GIT binary patch delta 49 zcmaE1zs{b^CDpumw2#g)j)%$GZo( nide?G8W=J}E63g4F Cg$w8a delta 105 zcmZ4Jc-xW7CDeV`_A&9nPVoYMcAFQeW>_A&9nPVoY+_L~>Vyd~0-XIq7zFI&-2+@j mEaP1b3>l)8WAvFpiUOQH4V-+Oz5oA55&)@>R!0&5sQ>^^$sO$g diff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot index 6b436f9cd95776c26bec09066eb621bf97219dc6..eeb40b360f7c1de93501e1ddcd7dab306a51113b 100644 GIT binary patch delta 48 zcmX@@Ink5LCD$Fl2~Uj?rfZDGG4*G;s29_Wu7LNdTliS{+FMqyhj-gB}zB diff --git a/tests/data/acpi/q35/DSDT.xapic b/tests/data/acpi/q35/DSDT.xapic index f47f09122287bdd20d7762d3d6dee6e05d944285..3aa86f07243f0449c7dc245650715d729744e3ee 100644 GIT binary patch delta 51 zcmcaPjcNWgCN7s?mk{}G1_nm&ja(_6TrN^E@xe~<0zQ(PD>`Q}@(S?8y9c<6u*JI? H7%~6=i=GYM delta 109 zcmbO~jp^nzCN7s?mypPA1_nm$ja(_6T;5VK@xe~<0?tyKD>`Q}x{I&{IQxY#2-wHF p2e^t@#=9CAGDIuK=re;<1vq;eIQckx|NoC908$^VjwAq50RX(s9~b}t diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 4be20b2cd1..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,37 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/pc/DSDT.nohpet", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.acpierst", -"tests/data/acpi/pc/DSDT.roothp", -"tests/data/acpi/pc/DSDT.hpbrroot", -"tests/data/acpi/pc/DSDT.hpbridge", -"tests/data/acpi/q35/DSDT", -"tests/data/acpi/q35/DSDT.tis.tpm2", -"tests/data/acpi/q35/DSDT.tis.tpm12", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.multi-bridge", -"tests/data/acpi/q35/DSDT.mmio64", -"tests/data/acpi/q35/DSDT.ipmibt", -"tests/data/acpi/q35/DSDT.cphp", -"tests/data/acpi/q35/DSDT.memhp", -"tests/data/acpi/q35/DSDT.numamem", -"tests/data/acpi/q35/DSDT.nohpet", -"tests/data/acpi/q35/DSDT.dimmpxm", -"tests/data/acpi/q35/DSDT.acpihmat", -"tests/data/acpi/q35/DSDT.acpierst", -"tests/data/acpi/q35/DSDT.applesmc", -"tests/data/acpi/q35/DSDT.pvpanic-isa", -"tests/data/acpi/q35/DSDT.ivrs", -"tests/data/acpi/q35/DSDT.viot", -"tests/data/acpi/q35/DSDT.cxl", -"tests/data/acpi/q35/DSDT.ipmismbus", -"tests/data/acpi/q35/DSDT.xapic", -"tests/data/acpi/q35/DSDT.acpihmat-noinitiator", -"tests/data/acpi/q35/DSDT.core-count2", From 5d1aee56676c82c3bf2f678a816c0821d362a77b Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:56 +0100 Subject: [PATCH 291/814] whitelist DSDT before adding endpoint devices to bridge testcases Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-25-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..571f14fd59 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.roothp", +"tests/data/acpi/pc/DSDT.hpbrroot", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.multi-bridge", From be8e333138d8e95602b0e1343a95a376785f6dc3 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:57 +0100 Subject: [PATCH 292/814] tests: acpi: add endpoint devices to bridges to make sure that they are enumerated or ignored as expected Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-26-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index a8c17461c8..22b22c403d 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -875,7 +875,9 @@ static void test_acpi_piix4_tcg_bridge(void) data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_vm_prepare("-S" " -device pci-bridge,chassis_nr=1" - " -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2", &data); + " -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2" + " -device pci-testdev,bus=pci.0,addr=5.0" + " -device pci-testdev,bus=pci.1", &data); /* hotplugged bridges section */ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr", @@ -884,6 +886,10 @@ static void test_acpi_piix4_tcg_bridge(void) "{'bus': 'pci.1', 'addr': '0xf.1', 'chassis_nr': 4 }"); qtest_qmp_device_add(data.qts, "pci-bridge", "hpbrhost", "{'bus': 'pci.0', 'addr': '4.0', 'chassis_nr': 5 }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d1", "{'bus': 'pci.0' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d2", "{'bus': 'pci.1' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d3", "{'bus': 'hpbr', " + "'addr': '1.0' }"); qtest_qmp_send(data.qts, "{'execute':'cont' }"); qtest_qmp_eventwait(data.qts, "RESUME"); @@ -907,7 +913,9 @@ static void test_acpi_piix4_no_root_hotplug(void) data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off " "-device pci-bridge,chassis_nr=1 " - "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1", &data); free_test_data(&data); } @@ -922,7 +930,9 @@ static void test_acpi_piix4_no_bridge_hotplug(void) data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off " "-device pci-bridge,chassis_nr=1 " - "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 ", &data); + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1,addr=2.0", &data); free_test_data(&data); } @@ -937,7 +947,9 @@ static void test_acpi_piix4_no_acpi_pci_hotplug(void) data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off " "-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1", &data); free_test_data(&data); } @@ -982,7 +994,9 @@ static void test_acpi_q35_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1", &data); + test_acpi_one("-device pci-bridge,chassis_nr=1,id=br1" + " -device pci-testdev,bus=pcie.0" + " -device pci-testdev,bus=br1", &data); free_test_data(&data); } @@ -1001,8 +1015,11 @@ static void test_acpi_q35_multif_bridge(void) " -device pci-bridge,bus=rp2,chassis_nr=4,id=br1" " -device pcie-root-port,id=rphptgt1,port=0x0,chassis=5,addr=2.1" " -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2" - " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3", - &data); + " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3" + " -device pci-testdev,bus=pcie.0,addr=2.4" + " -device pci-testdev,bus=pcie.0,addr=5.0" + " -device pci-testdev,bus=rp0,addr=0.0" + " -device pci-testdev,bus=br1", &data); /* hotplugged bridges section */ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1", @@ -1010,7 +1027,11 @@ static void test_acpi_q35_multif_bridge(void) qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr2-multiif", "{ 'bus': 'br1', 'addr': '2.2', 'chassis_nr': 129 }"); qtest_qmp_device_add(data.qts, "pcie-pci-bridge", "hpbr3", - "{'bus': 'rp0', 'addr': '0.0' }"); + "{'bus': 'rphptgt1', 'addr': '0.0' }"); + qtest_qmp_device_add(data.qts, "pcie-root-port", "hprp", + "{'bus': 'rphptgt2', 'addr': '0.0' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "hpnic", + "{'bus': 'rphptgt3', 'addr': '0.0' }"); qtest_qmp_send(data.qts, "{'execute':'cont' }"); qtest_qmp_eventwait(data.qts, "RESUME"); From 65e414a9dda6ea1bd52a74dc6e75003f3ca92003 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:58 +0100 Subject: [PATCH 293/814] tests: acpi: update expected blobs previous commit added endpoint devices to bridge testcases, which exposes extra non-hotpluggable slot in DSDT on bus where hotplug is not available. It should look like this (numbers may vary): + Device (S28) + { + Name (_ADR, 0x00050000) // _ADR: Address + } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-27-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT.hpbrroot | Bin 3064 -> 3081 bytes tests/data/acpi/pc/DSDT.roothp | Bin 9758 -> 9775 bytes tests/data/acpi/q35/DSDT.bridge | Bin 11458 -> 11475 bytes tests/data/acpi/q35/DSDT.multi-bridge | Bin 12358 -> 12375 bytes tests/qtest/bios-tables-test-allowed-diff.h | 4 ---- 5 files changed, 4 deletions(-) diff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot index 578468f4f00a9373366c92926b512c192dd6675b..a71ed4fbaa14be655c28a5e03e50157b4476e480 100644 GIT binary patch delta 53 zcmew%-YLQ566_Mf$-}_Fcyc4xJx(r1rI`3&r+5KR#m%2M*_Z^QoA`r`4B|QB9bJNe Hs#q8RhyD!~ delta 35 qcmeB__#w{a66_N4gPVbYQFkNPJx(qM#hCbDr+5Jmh0UKh*_Z&l3JL`P diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index fe502ed97751950cc245d728c873065f062c76b2..d58f4d2f0adbb86f8f6403a1cf9b13e1cabed035 100644 GIT binary patch delta 58 zcmbQ|v)+fxCDaNm`jT&21d00Qm}$^ZZW diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index c38b121ad90ecb896a906a50340ad5bd7d5453f9..3a01bb196b047b875be07be28d07f3139716e82f 100644 GIT binary patch delta 56 zcmX>Uc{!5HCDM9f^W)*?4>q)j=ZJT73F2X3 MU}o6-Q0pNh002i2`~Uy| delta 40 wcmcZ{c_@<0CDa6N&`CD)hUqa1ewBV$Z_uv5H1JHzH_a;x|@2kNph0{{nL3+(^^ diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 571f14fd59..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,5 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT.roothp", -"tests/data/acpi/pc/DSDT.hpbrroot", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.multi-bridge", From ab84fc1c353cd396b420e3c3360508ada594f6a9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:02:59 +0100 Subject: [PATCH 294/814] x86: pcihp: acpi: prepare slot ignore rule to work with self describing bridges Before switching pci bridges to AcpiDevAmlIf interface, ensure that ignored slots are handled correctly. (existing rule works but only if bridge doesn't have AcpiDevAmlIf interface). While at it rewrite related comments to be less confusing (hopefully). Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-28-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6368fcefa3..8045b20713 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -423,14 +423,22 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, hotpluggbale_slot = bsel && dc->hotpluggable && !cold_plugged_bridge; - /* - * allow describing coldplugged bridges in ACPI even if they are not - * on function 0, as they are not unpluggable, for all other devices - * generate description only for function 0 per slot, and for other - * functions if device on function provides its own AML - */ - if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) { - continue; + if (func) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { + continue; + } + } else if (!get_dev_aml_func(DEVICE(pdev))) { + /* + * Ignore all other devices on !0 functions unless they + * have AML description (i.e have get_dev_aml_func() != 0) + */ + continue; + } } } else { /* From d78644c7817617ea99b05ff30738580c56a6194f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:00 +0100 Subject: [PATCH 295/814] pci: acpi: wire up AcpiDevAmlIf interface to generic bridge ... so that the concrete impl. won't has to duplicate it every time. By default it doesn't do anything unless leaf class defines and sets AcpiDevAmlIfClass::build_dev_aml handler. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-29-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci_bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index b2b180edd6..a1a1cc861e 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -36,6 +36,7 @@ #include "qemu/module.h" #include "qemu/range.h" #include "qapi/error.h" +#include "hw/acpi/acpi_aml_interface.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -472,6 +473,10 @@ static const TypeInfo pci_bridge_type_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), .abstract = true, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void pci_bridge_register_types(void) From 6c36ec46b0d28f682eed1ce1278989535c1307dc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:01 +0100 Subject: [PATCH 296/814] pcihp: make bridge describe itself using AcpiDevAmlIfClass:build_dev_aml simplify build_append_pci_bus_devices() a bit by handling bridge specific logic in bridge dedicated AcpiDevAmlIfClass::build_dev_aml callback. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-30-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/Kconfig | 4 ++++ hw/acpi/meson.build | 4 +++- hw/acpi/pci-bridge-stub.c | 20 ++++++++++++++++++++ hw/acpi/pci-bridge.c | 27 +++++++++++++++++++++++++++ hw/i386/Kconfig | 1 + hw/i386/acpi-build.c | 17 ++--------------- hw/pci/pci_bridge.c | 9 +++++++++ include/hw/acpi/pci.h | 4 ++++ 8 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 hw/acpi/pci-bridge-stub.c create mode 100644 hw/acpi/pci-bridge.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 1f7803fdab..e07d3204eb 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -39,6 +39,10 @@ config ACPI_PCIHP bool depends on ACPI +config ACPI_PCI_BRIDGE + bool + depends on ACPI && PCI && ACPI_PCIHP + config ACPI_HMAT bool depends on ACPI diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 30054a8cdc..50b73129b4 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -19,6 +19,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c')) acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PIIX4', if_true: files('piix4.c')) +acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) @@ -30,9 +31,10 @@ if have_tpm acpi_ss.add(files('tpm.c')) endif softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c')) +softmmu_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c')) softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', 'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c', 'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c', 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c', - 'cxl-stub.c')) + 'cxl-stub.c', 'pci-bridge-stub.c')) diff --git a/hw/acpi/pci-bridge-stub.c b/hw/acpi/pci-bridge-stub.c new file mode 100644 index 0000000000..9d78638c48 --- /dev/null +++ b/hw/acpi/pci-bridge-stub.c @@ -0,0 +1,20 @@ +/* + * QEMU ACPI PCI bridge stub + * + * Copyright (c) 2023 Red Hat, Inc. + * + * Author: + * Igor Mammedov + * + * 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. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/pci.h" + +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope) +{ +} diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c new file mode 100644 index 0000000000..5f3ee5157f --- /dev/null +++ b/hw/acpi/pci-bridge.c @@ -0,0 +1,27 @@ +/* + * QEMU ACPI PCI bridge + * + * Copyright (c) 2023 Red Hat, Inc. + * + * Author: + * Igor Mammedov + * + * 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. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/pci.h" +#include "hw/pci/pci_bridge.h" +#include "hw/acpi/pcihp.h" + +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + PCIBridge *br = PCI_BRIDGE(adev); + + if (object_property_find(OBJECT(&br->sec_bus), ACPI_PCIHP_PROP_BSEL)) { + build_append_pci_bus_devices(scope, pci_bridge_get_sec_bus(br)); + } +} diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index c4fb5b49bd..1bf47b0b0b 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -58,6 +58,7 @@ config PC_ACPI select ACPI_X86 select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG + select ACPI_PCI_BRIDGE select ACPI_VIOT select SMBUS_EEPROM select PFLASH_CFI01 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8045b20713..49181a55b1 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -383,8 +383,7 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) aml_append(method, if_ctx); } -static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, - bool pcihp_bridge_en) +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) { Aml *dev, *notify_method = NULL, *method; QObject *bsel; @@ -406,7 +405,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ int adr = slot << 16 | func; bool hotpluggbale_slot = false; - bool bridge_in_acpi = false; bool cold_plugged_bridge = false; if (pdev) { @@ -418,7 +416,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, */ cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged; - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; hotpluggbale_slot = bsel && dc->hotpluggable && !cold_plugged_bridge; @@ -471,16 +468,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, call_dev_aml_func(DEVICE(pdev), dev); - if (bridge_in_acpi) { - /* - * device is coldplugged bridge, - * add child device descriptions into its scope - */ - PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); - - build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); - } - if (hotpluggbale_slot) { aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); /* add _EJ0 to make slot hotpluggable */ @@ -1704,7 +1691,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; Aml *scope = aml_scope("PCI0"); /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + build_append_pci_bus_devices(scope, bus); aml_append(sb_scope, scope); } } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index a1a1cc861e..dd5af508f9 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -37,6 +37,7 @@ #include "qemu/range.h" #include "qapi/error.h" #include "hw/acpi/acpi_aml_interface.h" +#include "hw/acpi/pci.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -468,10 +469,18 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, return 0; } +static void pci_bridge_class_init(ObjectClass *klass, void *data) +{ + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); + + adevc->build_dev_aml = build_pci_bridge_aml; +} + static const TypeInfo pci_bridge_type_info = { .name = TYPE_PCI_BRIDGE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), + .class_init = pci_bridge_class_init, .abstract = true, .interfaces = (InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index b5deee0a9d..467a99461c 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -27,6 +27,7 @@ #define HW_ACPI_PCI_H #include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/acpi_aml_interface.h" typedef struct AcpiMcfgInfo { uint64_t base; @@ -36,4 +37,7 @@ typedef struct AcpiMcfgInfo { void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, const char *oem_id, const char *oem_table_id); Aml *aml_pci_device_dsm(void); + +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); #endif From c6f16471959e49db40a41371134240a8bd464450 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:02 +0100 Subject: [PATCH 297/814] =?UTF-8?q?pci:=20make=20sure=20pci=5Fbus=5Fis=5Fe?= =?UTF-8?q?xpress()=20won't=20error=20out=20with=20"discards=20=E2=80=98co?= =?UTF-8?q?nst=E2=80=99=20qualifier"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit function doesn't need RW aceess to passed in bus pointer, make it const. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-31-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 2 +- include/hw/pci/pci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 39a7bb32aa..208c16f450 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -483,7 +483,7 @@ static void pci_bus_uninit(PCIBus *bus) pci_host_bus_unregister(BUS(bus)->parent); } -bool pci_bus_is_express(PCIBus *bus) +bool pci_bus_is_express(const PCIBus *bus) { return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 85ee458cd2..d5a40cd058 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -270,7 +270,7 @@ typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque); typedef void (*pci_bus_fn)(PCIBus *b, void *opaque); typedef void *(*pci_bus_ret_fn)(PCIBus *b, void *opaque); -bool pci_bus_is_express(PCIBus *bus); +bool pci_bus_is_express(const PCIBus *bus); void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, From a06c15a3b0778848c61b1bc3f03e41a3b585ea3d Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:03 +0100 Subject: [PATCH 298/814] pcihp: isolate rule whether slot should be described in DSDT Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-32-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 83 +++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 49181a55b1..b4c9ff4794 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -383,6 +383,42 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) aml_append(method, if_ctx); } +static bool is_devfn_ignored(const int devfn, const PCIBus *bus, + bool bus_has_hotplug) +{ + const PCIDevice *pdev = bus->devices[devfn]; + + if (pdev) { + if (PCI_FUNC(devfn)) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { + return true; + } + } else if (!get_dev_aml_func(DEVICE(pdev))) { + /* + * Ignore all other devices on !0 functions unless they + * have AML description (i.e have get_dev_aml_func() != 0) + */ + return true; + } + } + } else { /* non populated slots */ + /* + * hotplug is supported only for non-multifunction device + * so generate device description only for function 0 + */ + if (!bus_has_hotplug || PCI_FUNC(devfn) || + (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { + return true; + } + } + return false; +} + void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) { Aml *dev, *notify_method = NULL, *method; @@ -398,59 +434,26 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) } for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - DeviceClass *dc; PCIDevice *pdev = bus->devices[devfn]; int slot = PCI_SLOT(devfn); int func = PCI_FUNC(devfn); /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ int adr = slot << 16 | func; - bool hotpluggbale_slot = false; - bool cold_plugged_bridge = false; + bool hotpluggbale_slot = true; + + if (is_devfn_ignored(devfn, bus, !!bsel)) { + continue; + } if (pdev) { - dc = DEVICE_GET_CLASS(pdev); - /* * Cold plugged bridges aren't themselves hot-pluggable. * Hotplugged bridges *are* hot-pluggable. */ - cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && + bool cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged; - - hotpluggbale_slot = bsel && dc->hotpluggable && + hotpluggbale_slot = bsel && DEVICE_GET_CLASS(pdev)->hotpluggable && !cold_plugged_bridge; - - if (func) { - if (IS_PCI_BRIDGE(pdev)) { - /* - * Ignore only hotplugged PCI bridges on !0 functions, but - * allow describing cold plugged bridges on all functions - */ - if (DEVICE(pdev)->hotplugged) { - continue; - } - } else if (!get_dev_aml_func(DEVICE(pdev))) { - /* - * Ignore all other devices on !0 functions unless they - * have AML description (i.e have get_dev_aml_func() != 0) - */ - continue; - } - } - } else { - /* - * hotplug is supported only for non-multifunction device - * so generate device description only for function 0 - */ - if (bsel && !func) { - if (pci_bus_is_express(bus) && slot > 0) { - break; - } - /* mark it as empty hotpluggable slot */ - hotpluggbale_slot = true; - } else { - continue; - } } /* start to compose PCI device descriptor */ From 2e827356dfa87156a944a83217f675f212294398 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:04 +0100 Subject: [PATCH 299/814] tests: acpi: whitelist DSDT before decoupling PCI hotplug code from basic slots description Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-33-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..1983fa596b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,15 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.hpbridge", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.nohpet", +"tests/data/acpi/pc/DSDT.numamem", +"tests/data/acpi/pc/DSDT.roothp", +"tests/data/acpi/q35/DSDT.bridge", +"tests/data/acpi/q35/DSDT.multi-bridge", From 6fe5518e4fb75f6b3ae08d4b58da87fe8734a5de Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:05 +0100 Subject: [PATCH 300/814] pcihp: acpi: decouple hotplug and generic slots description Split build_append_pci_bus_devices() onto generic part that builds AML descriptions only for populated slots which is applicable to both hotplug disabled and enabled bridges. And a hotplug only part that complements generic AML with hotplug depended bits (that depend on BSEL), like _SUN/_EJ0 entries, dynamic _DSM. Hotplug part, will generate full 'Device' descriptors for non-populated slots (like it used to be) and complementary 'Scope' descriptors for populated slots that are hotplug capable. i.e. something like this: - ... + Name (BSEL, 0x03) + Scope (S00) + { + Name (ASUN, Zero) + Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method + { + Local0 = Package (0x02) + { + BSEL, + ASUN + } + Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) + } + [ ... other hotplug depended bits ] + } While generic build_append_pci_bus_devices() still calls hotplug part at its end it doesn't really depend on any hotplug bits anymore and later both could be completely separated when it's necessary. Main benefit though is that both build_append_pci_bus_devices() and build_append_pcihp_slots() become more readable and it makes easier to modify them with less risk of affecting another part. Also it opens possibility to re-use generic part elsewhere (microvm, arm/virt). Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-34-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 121 +++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 49 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index b4c9ff4794..2077efbee4 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -383,35 +383,40 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) aml_append(method, if_ctx); } -static bool is_devfn_ignored(const int devfn, const PCIBus *bus, - bool bus_has_hotplug) +static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) { const PCIDevice *pdev = bus->devices[devfn]; - if (pdev) { - if (PCI_FUNC(devfn)) { - if (IS_PCI_BRIDGE(pdev)) { - /* - * Ignore only hotplugged PCI bridges on !0 functions, but - * allow describing cold plugged bridges on all functions - */ - if (DEVICE(pdev)->hotplugged) { - return true; - } - } else if (!get_dev_aml_func(DEVICE(pdev))) { - /* - * Ignore all other devices on !0 functions unless they - * have AML description (i.e have get_dev_aml_func() != 0) - */ + if (PCI_FUNC(devfn)) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { return true; } + } else if (!get_dev_aml_func(DEVICE(pdev))) { + /* + * Ignore all other devices on !0 functions unless they + * have AML description (i.e have get_dev_aml_func() != 0) + */ + return true; } + } + return false; +} + +static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) +{ + if (bus->devices[devfn]) { + return is_devfn_ignored_generic(devfn, bus); } else { /* non populated slots */ - /* + /* * hotplug is supported only for non-multifunction device * so generate device description only for function 0 */ - if (!bus_has_hotplug || PCI_FUNC(devfn) || + if (PCI_FUNC(devfn) || (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { return true; } @@ -419,29 +424,23 @@ static bool is_devfn_ignored(const int devfn, const PCIBus *bus, return false; } -void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) +static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, + QObject *bsel) { - Aml *dev, *notify_method = NULL, *method; - QObject *bsel; int devfn; + Aml *dev, *notify_method = NULL, *method; + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - - aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); - notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); - } + aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); + notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { PCIDevice *pdev = bus->devices[devfn]; int slot = PCI_SLOT(devfn); - int func = PCI_FUNC(devfn); - /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ - int adr = slot << 16 | func; + int adr = slot << 16 | PCI_FUNC(devfn); bool hotpluggbale_slot = true; - if (is_devfn_ignored(devfn, bus, !!bsel)) { + if (is_devfn_ignored_hotplug(devfn, bus)) { continue; } @@ -452,24 +451,20 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) */ bool cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged; - hotpluggbale_slot = bsel && DEVICE_GET_CLASS(pdev)->hotpluggable && + hotpluggbale_slot = DEVICE_GET_CLASS(pdev)->hotpluggable && !cold_plugged_bridge; + dev = aml_scope("S%.02X", devfn); + } else { + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); } - /* start to compose PCI device descriptor */ - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); - - if (bsel) { - /* - * Can't declare _SUN here for every device as it changes 'slot' - * enumeration order in linux kernel, so use another variable for it - */ - aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); - aml_append(dev, aml_pci_device_dsm()); - } - - call_dev_aml_func(DEVICE(pdev), dev); + /* + * Can't declare _SUN here for every device as it changes 'slot' + * enumeration order in linux kernel, so use another variable for it + */ + aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); + aml_append(dev, aml_pci_device_dsm()); if (hotpluggbale_slot) { aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); @@ -486,9 +481,37 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } + aml_append(parent_scope, notify_method); +} + +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) +{ + QObject *bsel; + int devfn; + Aml *dev; + + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); + + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ + int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); + + if (!bus->devices[devfn] || is_devfn_ignored_generic(devfn, bus)) { + continue; + } + + /* start to compose PCI device descriptor */ + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + + call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); + + /* device descriptor has been composed, add it into parent context */ + aml_append(parent_scope, dev); + } if (bsel) { - aml_append(parent_scope, notify_method); + build_append_pcihp_slots(parent_scope, bus, bsel); } qobject_unref(bsel); From 912a5cf142e41110ec9cf0d0df3f412f24f32f12 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:06 +0100 Subject: [PATCH 301/814] tests: acpi: update expected blobs Expected change for non-populated slots is that thay are moved after non-hotpluggable PCI tree description. And expected change for hotplug capable populated slots is: - ... + Name (BSEL, 0x03) + Scope (S00) + { + Name (ASUN, Zero) + Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method + { + Local0 = Package (0x02) + { + BSEL, + ASUN + } + Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) + } [ ... other hotplug depended bits ] + } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-35-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT | Bin 6470 -> 6487 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 6430 -> 6453 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 7795 -> 7812 bytes tests/data/acpi/pc/DSDT.bridge | Bin 12634 -> 12699 bytes tests/data/acpi/pc/DSDT.cphp | Bin 6934 -> 6951 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 8124 -> 8141 bytes tests/data/acpi/pc/DSDT.hpbridge | Bin 6430 -> 6459 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 6542 -> 6559 bytes tests/data/acpi/pc/DSDT.memhp | Bin 7829 -> 7846 bytes tests/data/acpi/pc/DSDT.nohpet | Bin 6328 -> 6345 bytes tests/data/acpi/pc/DSDT.numamem | Bin 6476 -> 6493 bytes tests/data/acpi/pc/DSDT.roothp | Bin 9775 -> 9787 bytes tests/data/acpi/q35/DSDT.bridge | Bin 11475 -> 11481 bytes tests/data/acpi/q35/DSDT.multi-bridge | Bin 12375 -> 12423 bytes tests/qtest/bios-tables-test-allowed-diff.h | 14 -------------- 15 files changed, 14 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index c99179b35254725daeebb416400b1b6f9f1d74c4..1bc656f2a4897d2932d593e8768173e0d2597d45 100644 GIT binary patch delta 153 zcmX?Rblr%{CDvjwd^<$VE$S=nO c5&#+i5?}-g@CraQg9NykKq8yJ@CI=M05Z-dWdHyG delta 145 zcmca^bj*m$CDVFY6sgBY7x`GU9s%t#|s diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst index b0ae8c2cf52616836dae14c0a971f56fcfa7cdc8..0d4639906ddce689b3dcd9d749c79e3a511d548a 100644 GIT binary patch delta 186 zcmbPdwAF~qCD3oGPVoW`R|1?p4WgU4gAEMgIpQ5%f*7Kk z+@ymIEFe4{pbm!3f4EmL@@oYfLX`jonHVPDm+7WM<%S3U>8j5YPl0<`^96 p$1r)LkQ@(40H_Qkzz7oH6@Zup65wKji$IldF@r=lYw>;I0st<`Evf(j delta 162 zcmdmLG|!03CD2gC##=olR8$2hrARE|vmY}n+7LaLh;g@d>OKjtUM delta 151 zcmZp%{cOYK66_LEEXTmW$gz=YiGaH2)tLBTr+5L!s{ziQ1{_You09OWP5QwG2Jsy6 zjxIqA9FD=EehiZhMdc)-o4jO$4J;rMJU}BLl8hk9&9?(0_B+)Ci4ob bN{evB2OGLDEMWjKj9?675M#5Ea1b{De|;nj diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index 783a9d7b2964612626268905837d108679603432..4c2d77b8051de2ed21fe43c8283003d8083747f7 100644 GIT binary patch delta 429 zcmcbWG&`BgCDcc4D%mQ|kV{oV+!(>4L<;mH6B5VShAOj~)OosSeO|ky!i?LM~=-#Dwi3Z`GbuReqaH*7ASzQniVWyj8MVG z0Co!l$X1{z%qen6&fpb*gbUmia$pf;2gtF5oC>sfGM9iogbnmUG?WdrZu1%eO^(eE H^s1NuJu71d delta 124 zcmbQ8d@G5|CDp4a&F140H&DuV5fM2#sH=OXHNqTr(jnfhUg~!$@_Wr zSfZP}WG8d+8ExLcy@HX+fpu~upYh~$URmbu2FA&&_)J(qsu?Hm=JjQAIt)~3ym>3{ bf9}oUe6^gLH!5Fd-29X8HpgZ~{VFB^@bxCy diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index 659ad3d6b9026c090e0d8d8e21ece5df44249ec0..ef487176e117acf8f271d0a54bfad8dfa33ef696 100644 GIT binary patch delta 153 zcmbPcw%m-%CDvjwd^<$WFU40m$oAiSX4B|QB z9bJMLCdcrrNJKYz$p#x(K!kXJni)78gG2ooCqERB+g!)Hf>FSMHP{fU1t`zNFnI&N csC5E4mL1|=ZJT731WzD za+3}=uz>J*fI1j97YVIkvjwd^<$W9C?dxO Z60nG$>?fqcCIHqpSxZE9bCyUDHvq0iBSHWG delta 128 zcmX?WzsH`-CDm_q PNZ;h!!qS_oMS{2i7_T9@ diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge index b0ae8c2cf52616836dae14c0a971f56fcfa7cdc8..ce2e1430a38b467b212573a896b94c306caa12fb 100644 GIT binary patch delta 211 zcmbPdwA+ZwCDmiY DjxaJ> delta 203 zcmdmOG|!03CD=r+5L+n*q+A1{_You09OWP5QwG2Jsy6 zjxIqA9FD=EehiZz3d#vZH#sQ<8(2Ujcz{MQO#a8KvUwf%2S#xR)?h=Z7N86hL>m_q PNZ;hOywaO}`GU9s3acV^ diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index b2a7c042a902d1bbac79961639e27d302ad8799f..45b434d485444750cf00ebc1b2658f2fa40f0884 100644 GIT binary patch delta 169 zcmbPgyUdo$CDo#F+Yt_3)I8bmj72OAi~bHqEk1TjQ6 zxk(2bSU`9@KphO5y#-e=nrQ_aLX`jonHWSk;)4xc7?yw;Mlgmkh{53$?CQfHpb0W_ l@<#y`9uN~~pkr{TALHbYB67R}5W_$MTudO5&CbF>+yIwfDo6kT delta 145 zcmZ2xJJpuUCDB^zvD0TJQ>YG&YY3=Z{UocvHoZu4J(6^sH7tigs*EkJoDhROQE cs?s7H@xg{J3`-b53?mrB7{u5dA{@jG06rHa#Q*>R diff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet index b64da36b14edd13270dfd9db040a3b99219a36a0..dbed1404bb70eebf1c3cf0f882d3b4b7cccd53a8 100644 GIT binary patch delta 153 zcmdmCc+!x|CDo#F+Yt_3)I8bmj72OAi~bHqEk1TjQ6 zxk(2bSU`9@KphO5^SD=ZM2{3{Lcm*JuK>}P%Ad$^!yg}Rm8F(bN delta 152 zcmX?UxWkakCDB^zvD0TJQ>YG&YY3=Z{UocxeiZnFaS3Py1U)?h=Z7N9&6M4pQY cq(EAPBR<&Bg<%N;h+za{7=sv_%Xx#i0ZK(CPXGV_ diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem index f554b0b09db33fa90d65267c2687e90d4ab7d92e..6ee52f1230445c0dff01c77e72a74ca37e5864f1 100644 GIT binary patch delta 140 zcmX?Obk~T>CDbjFCwCDFU40m$oAiSX4B|QB z9bJMLI2?mR{TL=Y3dspYH+jhh8(2Ujcz{MQOy0w*vUv;l3Py1U)?h=Z7N86hL>m_q PNZ;gaUg^!;d_mj*>(n5J diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index d58f4d2f0adbb86f8f6403a1cf9b13e1cabed035..578de7540f6f09c05ad81f62abd142be8cb288ee 100644 GIT binary patch delta 128 zcmZ4Qv)hNuCD^cS3y&i8 delta 80 zcmV-W0I&bMOs`A|L{mgmFD3v00g8j5O8Jz3poad`Y}v?sGz)AQGOFI0QXoKo&W#< delta 76 zcmcZ^c{!5HCDb1Op<{LrPGhtQFh_2ii zs+<|Cat0*j5pJh~4K3lWVFtS1=P1JY(M@g#k$Ffyi*Di%Hb(fH4eC`^gyFWETNEcV z@(H-IfE79hhx&1`O>R_H*&L#Lhm#i)G%Ny|(2!9P5n*!)^9x~uNH8NLHk<1zFarSE CJzC`e delta 344 zcmZoqyq>`266_KZZot66_;w>#lN=WlV@!OoQ@lV2=QZp?+L!lRqk}Y*tdf!^tkf<`U)?!n8SESAiJ-)N@Yo diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 1983fa596b..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,15 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT", -"tests/data/acpi/pc/DSDT.acpierst", -"tests/data/acpi/pc/DSDT.acpihmat", -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.cphp", -"tests/data/acpi/pc/DSDT.dimmpxm", -"tests/data/acpi/pc/DSDT.hpbridge", -"tests/data/acpi/pc/DSDT.ipmikcs", -"tests/data/acpi/pc/DSDT.memhp", -"tests/data/acpi/pc/DSDT.nohpet", -"tests/data/acpi/pc/DSDT.numamem", -"tests/data/acpi/pc/DSDT.roothp", -"tests/data/acpi/q35/DSDT.bridge", -"tests/data/acpi/q35/DSDT.multi-bridge", From 9330847e6a3494a242a1180c8552ceab5d22b19d Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:07 +0100 Subject: [PATCH 302/814] tests: acpi: whitelist DSDT blobs before removing dynamic _DSM on coldplugged bridges Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-36-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..a83322cb08 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.roothp", +"tests/data/acpi/pc/DSDT.hpbridge", +"tests/data/acpi/q35/DSDT.multi-bridge", From 64a55106e4b9f5248f096bf158a9242c2b5cc8b9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:08 +0100 Subject: [PATCH 303/814] pcihp: acpi: ignore coldplugged bridges when composing hotpluggable slots coldplugged bridges are not unpluggable, so there is no need to describe slots where they are plugged as hotpluggable. To that effect we have a condition that marks slot as non-hotpluggable if it's populated by coldplugged bridge and prevents generation _SUN/_EJ0 objects for it. That leaves dynamic _DSM method on such slot (which also depends on BSEL and pcihp hardware). This _DSM method provides only dynamic acpi-index support so far, which is not actually used/supported by linux kernel for bridges and it's doubtful there will be need for it at all. So it's rather pointless to generate acpi-index related AML for bridges and we can simplify hotplug slots generator a bit more by completely ignoring coldplugged bridges on hotplug path. Another point in favor of dropping dynamic _DSM support, is that we can replace it with static _DSM if necessary since a slot with bridge can't change during VM runtime and without any dependency on ACPI PCI hotplug at that. Later I plan to implement bridge specific static _DSM PCI Firmware Specification 3.2 4.6.5. _DSM for Ignoring PCI Boot Configurations part of spec, to fix longstanding issue with fixed IO/MEM resource assignment that often leads to hotplugged device being in-operational within the guest due limited IO/MEM windows programmed on bridge at boot time. Expected change when coldplugged bridge is ignored by hotplug code, should look like: - Scope (S18) - { - Name (ASUN, 0x03) - Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method - { - Local0 = Package (0x02) - { - BSEL, - ASUN - } - Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) - } - } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-37-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2077efbee4..a02608c215 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -409,8 +409,11 @@ static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) { - if (bus->devices[devfn]) { - return is_devfn_ignored_generic(devfn, bus); + PCIDevice *pdev = bus->devices[devfn]; + if (pdev) { + return is_devfn_ignored_generic(devfn, bus) || + /* Cold plugged bridges aren't themselves hot-pluggable */ + (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); } else { /* non populated slots */ /* * hotplug is supported only for non-multifunction device @@ -445,14 +448,7 @@ static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, } if (pdev) { - /* - * Cold plugged bridges aren't themselves hot-pluggable. - * Hotplugged bridges *are* hot-pluggable. - */ - bool cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && - !DEVICE(pdev)->hotplugged; - hotpluggbale_slot = DEVICE_GET_CLASS(pdev)->hotpluggable && - !cold_plugged_bridge; + hotpluggbale_slot = DEVICE_GET_CLASS(pdev)->hotpluggable; dev = aml_scope("S%.02X", devfn); } else { dev = aml_device("S%.02X", devfn); From beb680ff28106b157f2d8372b2853753f96e15f5 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:09 +0100 Subject: [PATCH 304/814] tests: acpi: update expected blobs expected change is removal of dynamic _DSM bits from slots populated by coldplugged bridges (something like): - Scope (S18) - { - Name (ASUN, 0x03) - Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method - { - Local0 = Package (0x02) - { - BSEL, - ASUN - } - Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) - } - } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-38-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT.bridge | Bin 12699 -> 12614 bytes tests/data/acpi/pc/DSDT.hpbridge | Bin 6459 -> 6416 bytes tests/data/acpi/pc/DSDT.roothp | Bin 9787 -> 9745 bytes tests/data/acpi/q35/DSDT.multi-bridge | Bin 12423 -> 12337 bytes tests/qtest/bios-tables-test-allowed-diff.h | 4 ---- 5 files changed, 4 deletions(-) diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index 4c2d77b8051de2ed21fe43c8283003d8083747f7..d65d9f053910d4ef8a77fe7f9015768dd48a53f8 100644 GIT binary patch delta 65 zcmbQ8d@PB}CDtZT5319@y_I7a%Gt; VsHQpj0zcd4Dyf6qo72=xxdF4y6yg8? delta 64 zcmV-G0KfmnVw+g7N3-|#7j(@X;4Ves+ Wyd^5L9~$xt0VMlAQdeD diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge index ce2e1430a38b467b212573a896b94c306caa12fb..c8b388a85c8d7472a5370c9657fa2b4e1a897e38 100644 GIT binary patch delta 40 wcmdmOG{K0=CD=5C;GN diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index 578de7540f6f09c05ad81f62abd142be8cb288ee..657c8263f0c649abc806a67576fd74cb32af60c3 100644 GIT binary patch delta 58 zcmdn(Gtr03CDq3sF=HcFIX8FrT*jFAV5fM2rn#GYxPLG*wbyKJ<1OWxtRTd? OIg+o6bMq4A=}Z6+RuYx~ delta 66 zcmbQ}v)hNuCDpS6(Bxqf(41VLpdlc_<`U)?!o=Ye?CQhC3=!NcsH?yX0Mzgp3IG5A diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index a83322cb08..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,5 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/pc/DSDT.bridge", -"tests/data/acpi/pc/DSDT.roothp", -"tests/data/acpi/pc/DSDT.hpbridge", -"tests/data/acpi/q35/DSDT.multi-bridge", From 85ea72b96b746e2f88918e1b04495c9d329bb5c4 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:10 +0100 Subject: [PATCH 305/814] tests: acpi: whitelist DSDT before moving non-hotpluggble slots description from hotplug path Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-39-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test-allowed-diff.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..0adf61bac3 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,12 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT", +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/DSDT.acpihmat", +"tests/data/acpi/pc/DSDT.bridge", +"tests/data/acpi/pc/DSDT.cphp", +"tests/data/acpi/pc/DSDT.dimmpxm", +"tests/data/acpi/pc/DSDT.hpbridge", +"tests/data/acpi/pc/DSDT.ipmikcs", +"tests/data/acpi/pc/DSDT.memhp", +"tests/data/acpi/pc/DSDT.nohpet", +"tests/data/acpi/pc/DSDT.numamem", From 17f4cedba14f882a4816c5be320ca2192f04e31c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:11 +0100 Subject: [PATCH 306/814] pcihp: generate populated non-hotpluggble slot descriptions on non-hotplug path Generating slots descriptions populated by non-hotpluggable devices is akward at best and complicates hotplug path (build_append_pcihp_slots) needlessly, and builds only dynamic _DSM for such slots which is overlkill. Clean it up and let non-hotplug path (build_append_pci_bus_devices) to handle that task. Such clean up effectively drops dynamic _DSM methods on non-hotpluggable slots (even though bus itself is hotpluggable), but in practice it affects only built-in devices (ide controllers/various bridges) that don't use acpi-index anyways so effectively it doesn't matter (NICs are hotpluggble). Follow up series will add static _DSM for non-hotpluggble devices/buses that will not depend on ACPI PCI hotplug at all, and potentially would allows us to reuse non-hotplug path elsewhere (PBX/microvm/arm-virt), including new support for acpi-index for non-hotpluggable devices. Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-40-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index a02608c215..145389aa58 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -412,6 +412,7 @@ static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) PCIDevice *pdev = bus->devices[devfn]; if (pdev) { return is_devfn_ignored_generic(devfn, bus) || + !DEVICE_GET_CLASS(pdev)->hotpluggable || /* Cold plugged bridges aren't themselves hot-pluggable */ (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); } else { /* non populated slots */ @@ -438,17 +439,14 @@ static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - PCIDevice *pdev = bus->devices[devfn]; int slot = PCI_SLOT(devfn); int adr = slot << 16 | PCI_FUNC(devfn); - bool hotpluggbale_slot = true; if (is_devfn_ignored_hotplug(devfn, bus)) { continue; } - if (pdev) { - hotpluggbale_slot = DEVICE_GET_CLASS(pdev)->hotpluggable; + if (bus->devices[devfn]) { dev = aml_scope("S%.02X", devfn); } else { dev = aml_device("S%.02X", devfn); @@ -462,17 +460,15 @@ static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); aml_append(dev, aml_pci_device_dsm()); - if (hotpluggbale_slot) { - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - /* add _EJ0 to make slot hotpluggable */ - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); + aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); + /* add _EJ0 to make slot hotpluggable */ + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) + ); + aml_append(dev, method); - build_append_pcihp_notify_entry(notify_method, slot); - } + build_append_pcihp_notify_entry(notify_method, slot); /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); @@ -491,8 +487,9 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); + PCIDevice *pdev = bus->devices[devfn]; - if (!bus->devices[devfn] || is_devfn_ignored_generic(devfn, bus)) { + if (!pdev || is_devfn_ignored_generic(devfn, bus)) { continue; } From 4d6ee555ef649d00805a0730aa2e22fe152e90f0 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 12 Jan 2023 15:03:12 +0100 Subject: [PATCH 307/814] tests: acpi: update expected blobs Expected change removal of dynamic _DSM AML for non-hotpluggable hots-bridge, storage, isa bridge devices from PC machine blobs: - Scope (S00) - { - Name (ASUN, Zero) - Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method - { - Local0 = Package (0x02) - { - BSEL, - ASUN - } - Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) - } - } - - Scope (S08) - { - Name (ASUN, One) - Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method - { - Local0 = Package (0x02) - { - BSEL, - ASUN - } - Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) - } - } - - Scope (S10) - { - Name (ASUN, 0x02) - Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method - { - Local0 = Package (0x02) - { - BSEL, - ASUN - } - Return (PDSM (Arg0, Arg1, Arg2, Arg3, Local0)) - } - } Signed-off-by: Igor Mammedov Message-Id: <20230112140312.3096331-41-imammedo@redhat.com> --- tests/data/acpi/pc/DSDT | Bin 6487 -> 6360 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 6453 -> 6283 bytes tests/data/acpi/pc/DSDT.acpihmat | Bin 7812 -> 7685 bytes tests/data/acpi/pc/DSDT.bridge | Bin 12614 -> 12487 bytes tests/data/acpi/pc/DSDT.cphp | Bin 6951 -> 6824 bytes tests/data/acpi/pc/DSDT.dimmpxm | Bin 8141 -> 8014 bytes tests/data/acpi/pc/DSDT.hpbridge | Bin 6416 -> 6289 bytes tests/data/acpi/pc/DSDT.ipmikcs | Bin 6559 -> 6432 bytes tests/data/acpi/pc/DSDT.memhp | Bin 7846 -> 7719 bytes tests/data/acpi/pc/DSDT.nohpet | Bin 6345 -> 6218 bytes tests/data/acpi/pc/DSDT.numamem | Bin 6493 -> 6366 bytes tests/qtest/bios-tables-test-allowed-diff.h | 11 ----------- 12 files changed, 11 deletions(-) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index 1bc656f2a4897d2932d593e8768173e0d2597d45..0b475fb5a966543fef2cd7672a0b198838a63151 100644 GIT binary patch delta 40 wcmca^bi`|Vl`n`J03N^%qW}N^ delta 92 zcmca%c-@H0CDbUcyECDt1=UQs0S`?J*8l(j delta 71 zcmX?}cr1y_CDenv?HJYVZhX1{+w! bb2tWv`Y}#Ucsu?!`@?jHo diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index ef487176e117acf8f271d0a54bfad8dfa33ef696..754ab854dc48fc1af2d335e7269c23a056e66eb8 100644 GIT binary patch delta 40 wcmZ2(w!)OlCDW=VIc6o#F+Y&uwND`pvkxS|o@Y036s2$^ZZW delta 92 zcmX?Sch;WECDvQZ05_H!ZvX%Q diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge index c8b388a85c8d7472a5370c9657fa2b4e1a897e38..834c27002edbd3e2298a71c9ff1b501e3a3314f7 100644 GIT binary patch delta 40 wcmbPWG|`aDCDw>EckJ2UYJXa*Y?#B(?Xhx##0 f78H~N3s^t|7(oKO0$Ra_P!(KEAd$`Ic!RhBSb!F` diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index 45b434d485444750cf00ebc1b2658f2fa40f0884..2f895e9b385c1ae2f58c7ade4de02328b1be7356 100644 GIT binary patch delta 40 wcmZ2xyWED$CD=VIc6o#F+Y&uzXX@SAaSh;R@$00@>1nE(I) delta 92 zcmZ2(v&@#uCDo#F+Yu5G?0@SBlGKr`6DAfCf9IMk0} g@o#F+Yu5JFy^_!7LKr`6DAfCf9IMk0} gvLLSbkC5>CD`|Vn=gnP02yixaR2}S delta 92 zcmca-c-M%_CD|7PS7& Date: Mon, 23 Jan 2023 20:21:19 +0800 Subject: [PATCH 308/814] vhost-user: Skip unnecessary duplicated VHOST_USER_ADD/REM_MEM_REG requests The VHOST_USER_ADD/REM_MEM_REG requests should be categorized into non-vring specific messages, and should be sent only once. Signed-off-by: Minghao Yuan Message-Id: <20230123122119.194347-1-yuanmh12@chinatelecom.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-user.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 6c79da953b..eca9e104ba 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -459,6 +459,8 @@ static bool vhost_user_one_time_request(VhostUserRequest request) case VHOST_USER_SET_MEM_TABLE: case VHOST_USER_GET_QUEUE_NUM: case VHOST_USER_NET_SET_MTU: + case VHOST_USER_ADD_MEM_REG: + case VHOST_USER_REM_MEM_REG: return true; default: return false; From c45e7619dbe4033dfd525a417edb828af37a892e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Jan 2023 20:30:14 +0100 Subject: [PATCH 309/814] hw: Use TYPE_PCI_BUS definition where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the proper QOM type definition instead of magic string. This also helps during eventual refactor while using git-grep. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230117193014.83502-1-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Eric Auger --- hw/arm/smmu-common.c | 3 ++- hw/virtio/virtio-iommu.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 54186f31cb..733c964778 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -535,7 +535,8 @@ static void smmu_base_reset_hold(Object *obj) static Property smmu_dev_properties[] = { DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0), - DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, + TYPE_PCI_BUS, PCIBus *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 23c470977e..1cd258135d 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1366,7 +1366,8 @@ static const VMStateDescription vmstate_virtio_iommu = { }; static Property virtio_iommu_properties[] = { - DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, + TYPE_PCI_BUS, PCIBus *), DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true), DEFINE_PROP_END_OF_LIST(), }; From 4ffa3a1baa2678bb3c835aebdc3636e4a99c4ddf Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Jan 2023 13:51:32 +0100 Subject: [PATCH 310/814] tests/qtest/bios-tables-test: Make the test less verbose by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are facing the issues that our test logs in the gitlab CI are too big (and thus cut off). The bios-tables-test is one of the few qtests that prints many lines of output by default when running with V=1, so it contributes to this problem. Almost all other qtests are silent with V=1 and only print debug messages with V=2 and higher. Thus let's change the bios-tables-test to behave more like the other tests and only print the debug messages with V=2 (or higher). Signed-off-by: Thomas Huth Message-Id: <20230118125132.1694469-1-thuth@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov --- tests/qtest/bios-tables-test.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 22b22c403d..d8c8cda58e 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -24,7 +24,7 @@ * You will also notice that tests/qtest/bios-tables-test-allowed-diff.h lists * a bunch of files. This is your hint that you need to do the below: * 4. Run - * make check V=1 + * make check V=2 * this will produce a bunch of warnings about differences * beween actual and expected ACPI tables. If you have IASL installed, * they will also be disassembled so you can look at the disassembled @@ -108,6 +108,8 @@ static const char *iasl = CONFIG_IASL; static const char *iasl; #endif +static int verbosity_level; + static bool compare_signature(const AcpiSdtTable *sdt, const char *signature) { return !memcmp(sdt->aml, signature, 4); @@ -368,7 +370,7 @@ static GArray *load_expected_aml(test_data *data) gsize aml_len; GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); - if (getenv("V")) { + if (verbosity_level >= 2) { fputc('\n', stderr); } for (i = 0; i < data->tables->len; ++i) { @@ -383,7 +385,7 @@ static GArray *load_expected_aml(test_data *data) try_again: aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, sdt->aml, ext); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Looking for expected file '%s'\n", aml_file); } if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) { @@ -395,7 +397,7 @@ try_again: goto try_again; } g_assert(exp_sdt.aml_file); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Using expected file '%s'\n", aml_file); } ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml, @@ -503,7 +505,7 @@ static void test_acpi_asl(test_data *data) exp_sdt->aml, sdt->asl_file, sdt->aml_file, exp_sdt->asl_file, exp_sdt->aml_file); fflush(stderr); - if (getenv("V")) { + if (verbosity_level >= 1) { const char *diff_env = getenv("DIFF"); const char *diff_cmd = diff_env ? diff_env : "diff -U 16"; char *diff = g_strdup_printf("%s %s %s", diff_cmd, @@ -2042,8 +2044,13 @@ int main(int argc, char *argv[]) const char *arch = qtest_get_arch(); const bool has_kvm = qtest_has_accel("kvm"); const bool has_tcg = qtest_has_accel("tcg"); + char *v_env = getenv("V"); int ret; + if (v_env) { + verbosity_level = atoi(v_env); + } + g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { From f340a59d5a852d75ae34555723694c7e8eafbd0c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 19 Jan 2023 18:24:23 +0100 Subject: [PATCH 311/814] Revert "vhost-user: Monitor slave channel in vhost_user_read()" This reverts commit db8a3772e300c1a656331a92da0785d81667dc81. Motivation : this is breaking vhost-user with DPDK as reported in [0]. Received unexpected msg type. Expected 22 received 40 Fail to update device iotlb Received unexpected msg type. Expected 40 received 22 Received unexpected msg type. Expected 22 received 11 Fail to update device iotlb Received unexpected msg type. Expected 11 received 22 vhost VQ 1 ring restore failed: -71: Protocol error (71) Received unexpected msg type. Expected 22 received 11 Fail to update device iotlb Received unexpected msg type. Expected 11 received 22 vhost VQ 0 ring restore failed: -71: Protocol error (71) unable to start vhost net: 71: falling back on userspace virtio The failing sequence that leads to the first error is : - QEMU sends a VHOST_USER_GET_STATUS (40) request to DPDK on the master socket - QEMU starts a nested event loop in order to wait for the VHOST_USER_GET_STATUS response and to be able to process messages from the slave channel - DPDK sends a couple of legitimate IOTLB miss messages on the slave channel - QEMU processes each IOTLB request and sends VHOST_USER_IOTLB_MSG (22) updates on the master socket - QEMU assumes to receive a response for the latest VHOST_USER_IOTLB_MSG but it gets the response for the VHOST_USER_GET_STATUS instead The subsequent errors have the same root cause : the nested event loop breaks the order by design. It lures QEMU to expect responses to the latest message sent on the master socket to arrive first. Since this was only needed for DAX enablement which is still not merged upstream, just drop the code for now. A working solution will have to be merged later on. Likely protect the master socket with a mutex and service the slave channel with a separate thread, as discussed with Maxime in the mail thread below. [0] https://lore.kernel.org/qemu-devel/43145ede-89dc-280e-b953-6a2b436de395@redhat.com/ Reported-by: Yanghang Liu Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2155173 Signed-off-by: Greg Kurz Message-Id: <20230119172424.478268-2-groug@kaod.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Stefan Hajnoczi Acked-by: Maxime Coquelin --- hw/virtio/vhost-user.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index eca9e104ba..ad8883113b 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -356,35 +356,6 @@ end: return G_SOURCE_REMOVE; } -static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, - gpointer opaque); - -/* - * This updates the read handler to use a new event loop context. - * Event sources are removed from the previous context : this ensures - * that events detected in the previous context are purged. They will - * be re-detected and processed in the new context. - */ -static void slave_update_read_handler(struct vhost_dev *dev, - GMainContext *ctxt) -{ - struct vhost_user *u = dev->opaque; - - if (!u->slave_ioc) { - return; - } - - if (u->slave_src) { - g_source_destroy(u->slave_src); - g_source_unref(u->slave_src); - } - - u->slave_src = qio_channel_add_watch_source(u->slave_ioc, - G_IO_IN | G_IO_HUP, - slave_read, dev, NULL, - ctxt); -} - static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) { struct vhost_user *u = dev->opaque; @@ -406,7 +377,6 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) * be prepared for re-entrancy. So we create a new one and switch chr * to use it. */ - slave_update_read_handler(dev, ctxt); qemu_chr_be_update_read_handlers(chr->chr, ctxt); qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data); @@ -418,7 +388,6 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) * context that have been processed by the nested loop are purged. */ qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt); - slave_update_read_handler(dev, NULL); g_main_loop_unref(loop); g_main_context_unref(ctxt); @@ -1809,7 +1778,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) return -ECONNREFUSED; } u->slave_ioc = ioc; - slave_update_read_handler(dev, NULL); + u->slave_src = qio_channel_add_watch_source(u->slave_ioc, + G_IO_IN | G_IO_HUP, + slave_read, dev, NULL, NULL); if (reply_supported) { msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; From 4382138f642f69fdbc79ebf4e93d84be8061191f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 19 Jan 2023 18:24:24 +0100 Subject: [PATCH 312/814] Revert "vhost-user: Introduce nested event loop in vhost_user_read()" This reverts commit a7f523c7d114d445c5d83aecdba3efc038e5a692. The nested event loop is broken by design. It's only user was removed. Drop the code as well so that nobody ever tries to use it again. I had to fix a couple of trivial conflicts around return values because of 025faa872bcf ("vhost-user: stick to -errno error return convention"). Signed-off-by: Greg Kurz Message-Id: <20230119172424.478268-3-groug@kaod.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Maxime Coquelin --- hw/virtio/vhost-user.c | 65 ++++-------------------------------------- 1 file changed, 5 insertions(+), 60 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index ad8883113b..e68daa35d4 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) return 0; } -struct vhost_user_read_cb_data { - struct vhost_dev *dev; - VhostUserMsg *msg; - GMainLoop *loop; - int ret; -}; - -static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, - gpointer opaque) +static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) { - struct vhost_user_read_cb_data *data = opaque; - struct vhost_dev *dev = data->dev; - VhostUserMsg *msg = data->msg; struct vhost_user *u = dev->opaque; CharBackend *chr = u->user->chr; uint8_t *p = (uint8_t *) msg; @@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, r = vhost_user_read_header(dev, msg); if (r < 0) { - data->ret = r; - goto end; + return r; } /* validate message size is sane */ @@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, error_report("Failed to read msg header." " Size %d exceeds the maximum %zu.", msg->hdr.size, VHOST_USER_PAYLOAD_SIZE); - data->ret = -EPROTO; - goto end; + return -EPROTO; } if (msg->hdr.size) { @@ -346,53 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, int saved_errno = errno; error_report("Failed to read msg payload." " Read %d instead of %d.", r, msg->hdr.size); - data->ret = r < 0 ? -saved_errno : -EIO; - goto end; + return r < 0 ? -saved_errno : -EIO; } } -end: - g_main_loop_quit(data->loop); - return G_SOURCE_REMOVE; -} - -static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) -{ - struct vhost_user *u = dev->opaque; - CharBackend *chr = u->user->chr; - GMainContext *prev_ctxt = chr->chr->gcontext; - GMainContext *ctxt = g_main_context_new(); - GMainLoop *loop = g_main_loop_new(ctxt, FALSE); - struct vhost_user_read_cb_data data = { - .dev = dev, - .loop = loop, - .msg = msg, - .ret = 0 - }; - - /* - * We want to be able to monitor the slave channel fd while waiting - * for chr I/O. This requires an event loop, but we can't nest the - * one to which chr is currently attached : its fd handlers might not - * be prepared for re-entrancy. So we create a new one and switch chr - * to use it. - */ - qemu_chr_be_update_read_handlers(chr->chr, ctxt); - qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data); - - g_main_loop_run(loop); - - /* - * Restore the previous event loop context. This also destroys/recreates - * event sources : this guarantees that all pending events in the original - * context that have been processed by the nested loop are purged. - */ - qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt); - - g_main_loop_unref(loop); - g_main_context_unref(ctxt); - - return data.ret; + return 0; } static int process_message_reply(struct vhost_dev *dev, From f5cb612867d3b10b86d6361ba041767e02c1b127 Mon Sep 17 00:00:00 2001 From: Marcel Apfelbaum Date: Mon, 23 Jan 2023 17:42:05 +0000 Subject: [PATCH 313/814] docs/pcie.txt: Replace ioh3420 with pcie-root-port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not mention ioh3420 in the "how to" doc. The device still works and can be used by already existing setups, but no need to be mentioned. Suggested-by: Andrew Jones Reviewed-by: Laszlo Ersek Signed-off-by: Marcel Apfelbaum Signed-off-by: Daniel P. Berrangé Message-Id: <20230123174205.683979-1-berrange@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/pcie.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/pcie.txt b/docs/pcie.txt index 89e3502075..df49178311 100644 --- a/docs/pcie.txt +++ b/docs/pcie.txt @@ -48,8 +48,8 @@ Place only the following kinds of devices directly on the Root Complex: strangely when PCI Express devices are integrated with the Root Complex. - (2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express - hierarchies. + (2) PCI Express Root Ports (pcie-root-port), for starting exclusively + PCI Express hierarchies. (3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI hierarchies. @@ -70,7 +70,7 @@ Place only the following kinds of devices directly on the Root Complex: -device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z] PCI Express Root Ports and PCI Express to PCI bridges can be connected to the pcie.1 bus: - -device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ + -device pcie-root-port,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ -device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1 @@ -112,14 +112,14 @@ Plug only PCI Express devices into PCI Express Ports. ------------ 2.2.1 Plugging a PCI Express device into a PCI Express Root Port: - -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ + -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device ,bus=root_port1 2.2.2 Using multi-function PCI Express Root Ports: - -device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \ - -device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \ - -device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \ + -device pcie-root-port,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \ + -device pcie-root-port,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \ + -device pcie-root-port,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \ 2.2.3 Plugging a PCI Express device into a Switch: - -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ + -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \ -device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \ -device ,bus=downstream_port1 From e59a59a457bf135e2acd38df2ca7aca9c93e53d1 Mon Sep 17 00:00:00 2001 From: Sebastian Mitterle Date: Fri, 27 Jan 2023 13:33:49 +0100 Subject: [PATCH 314/814] docs/s390x/pcidevices: document pci devices on s390x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some documentation about the zpci device and how to use it with pci devices on s390x. Used source: Cornelia Huck's blog post https://people.redhat.com/~cohuck/2018/02/19/notes-on-pci-on-s390x.html Signed-off-by: Sebastian Mitterle Reviewed-by: Cédric Le Goater Message-Id: <20230127123349.55294-1-smitterl@redhat.com> Reviewed-by: Cornelia Huck Signed-off-by: Thomas Huth --- docs/system/s390x/pcidevices.rst | 41 ++++++++++++++++++++++++++++++++ docs/system/target-s390x.rst | 1 + 2 files changed, 42 insertions(+) create mode 100644 docs/system/s390x/pcidevices.rst diff --git a/docs/system/s390x/pcidevices.rst b/docs/system/s390x/pcidevices.rst new file mode 100644 index 0000000000..628effa2f4 --- /dev/null +++ b/docs/system/s390x/pcidevices.rst @@ -0,0 +1,41 @@ +PCI devices on s390x +==================== + +PCI devices on s390x work differently than on other architectures and need to +be configured in a slightly different way. + +Every PCI device is linked with an additional ``zpci`` device. +While the ``zpci`` device will be autogenerated if not specified, it is +recommended to specify it explicitly so that you can pass s390-specific +PCI configuration. + +For example, in order to pass a PCI device ``0000:00:00.0`` through to the +guest, you would specify:: + + qemu-system-s390x ... \ + -device zpci,uid=1,fid=0,target=hostdev0,id=zpci1 \ + -device vfio-pci,host=0000:00:00.0,id=hostdev0 + +Here, the zpci device is joined with the PCI device via the ``target`` property. + +Note that we don't set bus, slot or function here for the guest as is common in +other PCI implementations. Topology information is not available on s390x, and +the guest will not see any of the bus, slot or function information specified +on the command line. + +Instead, ``uid`` and ``fid`` determine how the device is presented to the guest +operating system. + +In case of Linux, ``uid`` will be used in the ``domain`` part of the PCI +identifier, and ``fid`` identifies the physical slot, i.e.:: + + qemu-system-s390x ... \ + -device zpci,uid=7,fid=8,target=hostdev0,id=zpci1 \ + ... + +will be presented in the guest as:: + + # lspci -v + 0007:00:00.0 ... + Physical Slot: 00000008 + ... diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index c636f64113..f6f11433c7 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -26,6 +26,7 @@ or vfio-ap is also available. s390x/css s390x/3270 s390x/vfio-ccw + s390x/pcidevices Architectural features ====================== From 637d18090ed2fc8d5edea0c0c584291cb792a086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 23 Jan 2023 09:39:56 +0100 Subject: [PATCH 315/814] qapi, audio: add query-audiodev command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Way back in QEMU 4.0, the -audiodev command line option was introduced for configuring audio backends. This CLI option does not use QemuOpts so it is not visible for introspection in 'query-command-line-options', instead using the QAPI Audiodev type. Unfortunately there is also no QMP command that uses the Audiodev type, so it is not introspectable with 'query-qmp-schema' either. This introduces a 'query-audiodev' command that simply reflects back the list of configured -audiodev command line options. This alone is maybe not very useful by itself, but it makes Audiodev introspectable via 'query-qmp-schema', so that libvirt (and other upper layer tools) can discover the available audiodevs. Signed-off-by: Daniel P. Berrangé [thuth: Update for upcoming QEMU v8.0, and use QAPI_LIST_PREPEND] Message-Id: <20230123083957.20349-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- audio/audio.c | 12 ++++++++++++ qapi/audio.json | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index d849a94a81..6f270c07b7 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -28,8 +28,10 @@ #include "monitor/monitor.h" #include "qemu/timer.h" #include "qapi/error.h" +#include "qapi/clone-visitor.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-audio.h" +#include "qapi/qapi-commands-audio.h" #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/help_option.h" @@ -2311,3 +2313,13 @@ size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, return bytes; } + +AudiodevList *qmp_query_audiodevs(Error **errp) +{ + AudiodevList *ret = NULL; + AudiodevListEntry *e; + QSIMPLEQ_FOREACH(e, &audiodevs, next) { + QAPI_LIST_PREPEND(ret, QAPI_CLONE(Audiodev, e->dev)); + } + return ret; +} diff --git a/qapi/audio.json b/qapi/audio.json index 1e0a24bdfc..c7aafa2763 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -443,3 +443,16 @@ 'sndio': 'AudiodevSndioOptions', 'spice': 'AudiodevGenericOptions', 'wav': 'AudiodevWavOptions' } } + +## +# @query-audiodevs: +# +# Returns information about audiodev configuration +# +# Returns: array of @Audiodev +# +# Since: 8.0 +# +## +{ 'command': 'query-audiodevs', + 'returns': ['Audiodev'] } From 7a92a8573c81162f75d71873be32c65f8aedd07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 23 Jan 2023 09:39:57 +0100 Subject: [PATCH 316/814] qapi, audio: Make introspection reflect build configuration more closely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the -audiodev accepts any audiodev type regardless of what is built in to QEMU. An error only occurs later at runtime when a sound device tries to use the audio backend. With this change QEMU will immediately reject -audiodev args that are not compiled into the binary. The QMP schema will also be introspectable to identify what is compiled in. This also helps to avoid compiling code that is not required in the binary. Note: When building the audiodevs as modules, the patch only compiles out code for modules that we don't build at all. Signed-off-by: Daniel P. Berrangé [thuth: Rebase, take sndio and dbus devices into account] Message-Id: <20230123083957.20349-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- audio/audio.c | 20 +++++++++++++++++++ audio/audio_legacy.c | 41 ++++++++++++++++++++++++++++++++++++++- audio/audio_template.h | 20 +++++++++++++++++++ qapi/audio.json | 44 ++++++++++++++++++++++++++++++------------ 4 files changed, 112 insertions(+), 13 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 6f270c07b7..4290309d18 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2048,16 +2048,36 @@ void audio_create_pdos(Audiodev *dev) break CASE(NONE, none, ); +#ifdef CONFIG_AUDIO_ALSA CASE(ALSA, alsa, Alsa); +#endif +#ifdef CONFIG_AUDIO_COREAUDIO CASE(COREAUDIO, coreaudio, Coreaudio); +#endif +#ifdef CONFIG_DBUS_DISPLAY CASE(DBUS, dbus, ); +#endif +#ifdef CONFIG_AUDIO_DSOUND CASE(DSOUND, dsound, ); +#endif +#ifdef CONFIG_AUDIO_JACK CASE(JACK, jack, Jack); +#endif +#ifdef CONFIG_AUDIO_OSS CASE(OSS, oss, Oss); +#endif +#ifdef CONFIG_AUDIO_PA CASE(PA, pa, Pa); +#endif +#ifdef CONFIG_AUDIO_SDL CASE(SDL, sdl, Sdl); +#endif +#ifdef CONFIG_AUDIO_SNDIO CASE(SNDIO, sndio, ); +#endif +#ifdef CONFIG_SPICE CASE(SPICE, spice, ); +#endif CASE(WAV, wav, ); case AUDIODEV_DRIVER__MAX: diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c index 18a89ffffb..b848001ff7 100644 --- a/audio/audio_legacy.c +++ b/audio/audio_legacy.c @@ -90,6 +90,7 @@ static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst) } +#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_DSOUND) static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst) { const char *val = getenv(env); @@ -98,15 +99,20 @@ static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst) *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_COREAUDIO) || \ + defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ + defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t frames_to_usecs(uint32_t frames, AudiodevPerDirectionOptions *pdo) { uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100; return (frames * 1000000 + freq / 2) / freq; } +#endif - +#ifdef CONFIG_AUDIO_COREAUDIO static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst, AudiodevPerDirectionOptions *pdo) { @@ -116,14 +122,19 @@ static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ + defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t samples_to_usecs(uint32_t samples, AudiodevPerDirectionOptions *pdo) { uint32_t channels = pdo->has_channels ? pdo->channels : 2; return frames_to_usecs(samples / channels, pdo); } +#endif +#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst, AudiodevPerDirectionOptions *pdo) { @@ -133,7 +144,9 @@ static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo) { AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16; @@ -150,8 +163,11 @@ static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif /* backend specific functions */ + +#ifdef CONFIG_AUDIO_ALSA /* ALSA */ static void handle_alsa_per_direction( AudiodevAlsaPerDirectionOptions *apdo, const char *prefix) @@ -197,7 +213,9 @@ static void handle_alsa(Audiodev *dev) get_millis_to_usecs("QEMU_ALSA_THRESHOLD", &aopt->threshold, &aopt->has_threshold); } +#endif +#ifdef CONFIG_AUDIO_COREAUDIO /* coreaudio */ static void handle_coreaudio(Audiodev *dev) { @@ -210,7 +228,9 @@ static void handle_coreaudio(Audiodev *dev) &dev->u.coreaudio.out->buffer_count, &dev->u.coreaudio.out->has_buffer_count); } +#endif +#ifdef CONFIG_AUDIO_DSOUND /* dsound */ static void handle_dsound(Audiodev *dev) { @@ -225,7 +245,9 @@ static void handle_dsound(Audiodev *dev) &dev->u.dsound.in->has_buffer_length, dev->u.dsound.in); } +#endif +#ifdef CONFIG_AUDIO_OSS /* OSS */ static void handle_oss_per_direction( AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env, @@ -253,7 +275,9 @@ static void handle_oss(Audiodev *dev) get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive); get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy); } +#endif +#ifdef CONFIG_AUDIO_PA /* pulseaudio */ static void handle_pa_per_direction( AudiodevPaPerDirectionOptions *ppdo, const char *env) @@ -277,7 +301,9 @@ static void handle_pa(Audiodev *dev) get_str("QEMU_PA_SERVER", &dev->u.pa.server); } +#endif +#ifdef CONFIG_AUDIO_SDL /* SDL */ static void handle_sdl(Audiodev *dev) { @@ -286,6 +312,7 @@ static void handle_sdl(Audiodev *dev) &dev->u.sdl.out->has_buffer_length, qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out)); } +#endif /* wav */ static void handle_wav(Audiodev *dev) @@ -345,29 +372,41 @@ static AudiodevListEntry *legacy_opt(const char *drvname) } switch (e->dev->driver) { +#ifdef CONFIG_AUDIO_ALSA case AUDIODEV_DRIVER_ALSA: handle_alsa(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_COREAUDIO case AUDIODEV_DRIVER_COREAUDIO: handle_coreaudio(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_DSOUND case AUDIODEV_DRIVER_DSOUND: handle_dsound(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_OSS case AUDIODEV_DRIVER_OSS: handle_oss(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_PA case AUDIODEV_DRIVER_PA: handle_pa(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_SDL case AUDIODEV_DRIVER_SDL: handle_sdl(e->dev); break; +#endif case AUDIODEV_DRIVER_WAV: handle_wav(e->dev); diff --git a/audio/audio_template.h b/audio/audio_template.h index 720a32e57e..42b4712acb 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -326,27 +326,47 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev) switch (dev->driver) { case AUDIODEV_DRIVER_NONE: return dev->u.none.TYPE; +#ifdef CONFIG_AUDIO_ALSA case AUDIODEV_DRIVER_ALSA: return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE); +#endif +#ifdef CONFIG_AUDIO_COREAUDIO case AUDIODEV_DRIVER_COREAUDIO: return qapi_AudiodevCoreaudioPerDirectionOptions_base( dev->u.coreaudio.TYPE); +#endif +#ifdef CONFIG_DBUS_DISPLAY case AUDIODEV_DRIVER_DBUS: return dev->u.dbus.TYPE; +#endif +#ifdef CONFIG_AUDIO_DSOUND case AUDIODEV_DRIVER_DSOUND: return dev->u.dsound.TYPE; +#endif +#ifdef CONFIG_AUDIO_JACK case AUDIODEV_DRIVER_JACK: return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE); +#endif +#ifdef CONFIG_AUDIO_OSS case AUDIODEV_DRIVER_OSS: return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE); +#endif +#ifdef CONFIG_AUDIO_PA case AUDIODEV_DRIVER_PA: return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE); +#endif +#ifdef CONFIG_AUDIO_SDL case AUDIODEV_DRIVER_SDL: return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE); +#endif +#ifdef CONFIG_AUDIO_SNDIO case AUDIODEV_DRIVER_SNDIO: return dev->u.sndio.TYPE; +#endif +#ifdef CONFIG_SPICE case AUDIODEV_DRIVER_SPICE: return dev->u.spice.TYPE; +#endif case AUDIODEV_DRIVER_WAV: return dev->u.wav.TYPE; diff --git a/qapi/audio.json b/qapi/audio.json index c7aafa2763..4e54c00f51 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -408,8 +408,18 @@ # Since: 4.0 ## { 'enum': 'AudiodevDriver', - 'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa', - 'sdl', 'sndio', 'spice', 'wav' ] } + 'data': [ 'none', + { 'name': 'alsa', 'if': 'CONFIG_AUDIO_ALSA' }, + { 'name': 'coreaudio', 'if': 'CONFIG_AUDIO_COREAUDIO' }, + { 'name': 'dbus', 'if': 'CONFIG_DBUS_DISPLAY' }, + { 'name': 'dsound', 'if': 'CONFIG_AUDIO_DSOUND' }, + { 'name': 'jack', 'if': 'CONFIG_AUDIO_JACK' }, + { 'name': 'oss', 'if': 'CONFIG_AUDIO_OSS' }, + { 'name': 'pa', 'if': 'CONFIG_AUDIO_PA' }, + { 'name': 'sdl', 'if': 'CONFIG_AUDIO_SDL' }, + { 'name': 'sndio', 'if': 'CONFIG_AUDIO_SNDIO' }, + { 'name': 'spice', 'if': 'CONFIG_SPICE' }, + 'wav' ] } ## # @Audiodev: @@ -432,16 +442,26 @@ 'discriminator': 'driver', 'data': { 'none': 'AudiodevGenericOptions', - 'alsa': 'AudiodevAlsaOptions', - 'coreaudio': 'AudiodevCoreaudioOptions', - 'dbus': 'AudiodevGenericOptions', - 'dsound': 'AudiodevDsoundOptions', - 'jack': 'AudiodevJackOptions', - 'oss': 'AudiodevOssOptions', - 'pa': 'AudiodevPaOptions', - 'sdl': 'AudiodevSdlOptions', - 'sndio': 'AudiodevSndioOptions', - 'spice': 'AudiodevGenericOptions', + 'alsa': { 'type': 'AudiodevAlsaOptions', + 'if': 'CONFIG_AUDIO_ALSA' }, + 'coreaudio': { 'type': 'AudiodevCoreaudioOptions', + 'if': 'CONFIG_AUDIO_COREAUDIO' }, + 'dbus': { 'type': 'AudiodevGenericOptions', + 'if': 'CONFIG_DBUS_DISPLAY' }, + 'dsound': { 'type': 'AudiodevDsoundOptions', + 'if': 'CONFIG_AUDIO_DSOUND' }, + 'jack': { 'type': 'AudiodevJackOptions', + 'if': 'CONFIG_AUDIO_JACK' }, + 'oss': { 'type': 'AudiodevOssOptions', + 'if': 'CONFIG_AUDIO_OSS' }, + 'pa': { 'type': 'AudiodevPaOptions', + 'if': 'CONFIG_AUDIO_PA' }, + 'sdl': { 'type': 'AudiodevSdlOptions', + 'if': 'CONFIG_AUDIO_SDL' }, + 'sndio': { 'type': 'AudiodevSndioOptions', + 'if': 'CONFIG_AUDIO_SNDIO' }, + 'spice': { 'type': 'AudiodevGenericOptions', + 'if': 'CONFIG_SPICE' }, 'wav': 'AudiodevWavOptions' } } ## From 7c4f71506f785da0eb4eae98753fe689f4bab351 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 30 Jan 2023 11:44:41 +0100 Subject: [PATCH 317/814] gitlab-ci.d/buildtest: Remove ppc-softmmu from the clang-system job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are also compile-testing ppc64-softmmu with clang in the "tsan-build" job, and ppc64-softmmu covers pretty much the same code as ppc-softmmu, so we should not lose much test coverage here by removing ppc-softmmu from the "clang-system" job. Message-Id: <20230130104446.1286773-2-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index f09a898c3e..406608e5fc 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -316,8 +316,7 @@ clang-system: IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ --extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined - TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu - ppc-softmmu s390x-softmmu + TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu s390x-softmmu MAKE_CHECK_ARGS: check-qtest check-tcg clang-user: From f2e57851b831922625f9d364d78c11a0258331a6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 30 Jan 2023 11:44:43 +0100 Subject: [PATCH 318/814] tests/qtest/display-vga-test: Add proper checks if a device is available display-vga-test currently tries to guess the usable VGA devices according to the target architecture that is used for the test. This of course does not work if QEMU has been built with the "--without-default-devices" configure switch. To fix this, use the qtest_has_device() function for the decision instead. This way we can also consolidate most of the test functions into one single function (that takes a parameter with the device name now), except for the multihead test that tries to instantiate two devices and thus is a little bit different. Message-Id: <20230130104446.1286773-4-thuth@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- tests/qtest/display-vga-test.c | 65 +++++++++++++--------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/tests/qtest/display-vga-test.c b/tests/qtest/display-vga-test.c index ace3bb28e0..75b341a9c6 100644 --- a/tests/qtest/display-vga-test.c +++ b/tests/qtest/display-vga-test.c @@ -8,61 +8,46 @@ */ #include "qemu/osdep.h" -#include "libqtest-single.h" - -static void pci_cirrus(void) -{ - qtest_start("-vga none -device cirrus-vga"); - qtest_end(); -} - -static void pci_stdvga(void) -{ - qtest_start("-vga none -device VGA"); - qtest_end(); -} - -static void pci_secondary(void) -{ - qtest_start("-vga none -device secondary-vga"); - qtest_end(); -} +#include "libqtest.h" static void pci_multihead(void) { - qtest_start("-vga none -device VGA -device secondary-vga"); - qtest_end(); + QTestState *qts; + + qts = qtest_init("-vga none -device VGA -device secondary-vga"); + qtest_quit(qts); } -static void pci_virtio_gpu(void) +static void test_vga(gconstpointer data) { - qtest_start("-vga none -device virtio-gpu-pci"); - qtest_end(); -} + QTestState *qts; -static void pci_virtio_vga(void) -{ - qtest_start("-vga none -device virtio-vga"); - qtest_end(); + qts = qtest_initf("-vga none -device %s", (const char *)data); + qtest_quit(qts); } int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); + static const char *devices[] = { + "cirrus-vga", + "VGA", + "secondary-vga", + "virtio-gpu-pci", + "virtio-vga" + }; g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "alpha") == 0 || strcmp(arch, "i386") == 0 || - strcmp(arch, "mips") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("/display/pci/cirrus", pci_cirrus); + for (int i = 0; i < ARRAY_SIZE(devices); i++) { + if (qtest_has_device(devices[i])) { + char *testpath = g_strdup_printf("/display/pci/%s", devices[i]); + qtest_add_data_func(testpath, devices[i], test_vga); + g_free(testpath); + } } - qtest_add_func("/display/pci/stdvga", pci_stdvga); - qtest_add_func("/display/pci/secondary", pci_secondary); - qtest_add_func("/display/pci/multihead", pci_multihead); - qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu); - if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") || - g_str_equal(arch, "hppa") || g_str_equal(arch, "ppc64")) { - qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga); + + if (qtest_has_device("secondary-vga")) { + qtest_add_func("/display/pci/multihead", pci_multihead); } return g_test_run(); From e030d08c2fc02743dd37e3d2e6e28fdd739590b9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 30 Jan 2023 11:44:44 +0100 Subject: [PATCH 319/814] gitlab-ci.d/buildtest: Merge the --without-default-* jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's safe some CI minutes by merging these two jobs. We can now also drop "--disable-capstone" since the capstone submodule has been removed a while ago. We should rather test --disable-fdt now to check a compilation without the "dtc" submodule (for this we have to drop i386-softmmu from the target list unfortunately). Additionally, the qtests with s390x and sh4 are not read for "--without-default-devices" yet, so we can only test mips64 and avr here now. Message-Id: <20230130104446.1286773-5-thuth@redhat.com> Reviewed-by: Alex Bennée Reviewed-by: Fabiano Rosas Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 406608e5fc..1c35cbfa10 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -557,29 +557,22 @@ build-coroutine-sigaltstack: MAKE_CHECK_ARGS: check-unit # Check our reduced build configurations -build-without-default-devices: +build-without-defaults: extends: .native_build_job_template needs: job: amd64-centos8-container variables: IMAGE: centos8 - CONFIGURE_ARGS: --without-default-devices --disable-user - -build-without-default-features: - extends: .native_build_job_template - needs: - job: amd64-fedora-container - variables: - IMAGE: fedora CONFIGURE_ARGS: + --without-default-devices --without-default-features - --disable-capstone + --disable-fdt --disable-pie --disable-qom-cast-debug --disable-strip - TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu + TARGETS: avr-softmmu mips64-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user - MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow + MAKE_CHECK_ARGS: check-unit check-qtest-avr check-qtest-mips64 build-libvhost-user: extends: .base_job_template From c1fc91b82545a2b8ab73f81e5b7b6b0fec292ea1 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 26 Jan 2023 13:52:34 +0100 Subject: [PATCH 320/814] m68k: fix 'bkpt' instruction in softmmu mode In linux-user mode, 'bkpt' generates an EXP_DEBUG exception to allow QEMU gdb server to intercept and manage the operation with an external debugger. In softmmu mode, the instruction must generate an illegal instruction exception as it is on real hardware to be managed by the kernel. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1462 Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20230126125234.3186042-1-laurent@vivier.eu> Signed-off-by: Laurent Vivier --- target/m68k/translate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 18418312b1..31178c3b1d 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2774,7 +2774,11 @@ DISAS_INSN(swap) DISAS_INSN(bkpt) { +#if defined(CONFIG_SOFTMMU) + gen_exception(s, s->base.pc_next, EXCP_ILLEGAL); +#else gen_exception(s, s->base.pc_next, EXCP_DEBUG); +#endif } DISAS_INSN(pea) From 07a4e1f8e5418f36424cd57d5d061b090a238c65 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 12 Jan 2023 20:14:54 +0100 Subject: [PATCH 321/814] qemu-iotests: Test qemu-img bitmap/commit exit code on error This tests that when an error happens while writing back bitmaps to the image file in qcow2_inactivate(), 'qemu-img bitmap/commit' actually return an error value in their exit code instead of making the operation look successful to scripts. Signed-off-by: Kevin Wolf Message-Id: <20230112191454.169353-5-kwolf@redhat.com> Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- .../qemu-iotests/tests/qemu-img-close-errors | 96 +++++++++++++++++++ .../tests/qemu-img-close-errors.out | 23 +++++ 2 files changed, 119 insertions(+) create mode 100755 tests/qemu-iotests/tests/qemu-img-close-errors create mode 100644 tests/qemu-iotests/tests/qemu-img-close-errors.out diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors b/tests/qemu-iotests/tests/qemu-img-close-errors new file mode 100755 index 0000000000..50bfb6cfa2 --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-close-errors @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# group: rw auto quick +# +# Check that errors while closing the image, in particular writing back dirty +# bitmaps, is correctly reported with a failing qemu-img exit code. +# +# Copyright (C) 2023 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 . +# + +# creator +owner=kwolf@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +cd .. +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +size=1G + +# The error we are going to use is ENOSPC. Depending on how many bitmaps we +# create in the backing file (and therefore increase the used up space), we get +# failures in different places. With a low number, only merging the bitmap +# fails, whereas with a higher number, already 'qemu-img commit' fails. +for max_bitmap in 6 7; do + echo + echo "=== Test with $max_bitmap bitmaps ===" + + TEST_IMG="$TEST_IMG.base" _make_test_img -q $size + for i in $(seq 1 $max_bitmap); do + $QEMU_IMG bitmap --add "$TEST_IMG.base" "stale-bitmap-$i" + done + + # Simulate a block device of 128 MB by resizing the image file accordingly + # and then enforcing the size with the raw driver + $QEMU_IO -f raw -c "truncate 128M" "$TEST_IMG.base" + BASE_JSON='json:{ + "driver": "qcow2", + "file": { + "driver": "raw", + "size": 134217728, + "file": { + "driver": "file", + "filename":"'"$TEST_IMG.base"'" + } + } + }' + + _make_test_img -q -b "$BASE_JSON" -F $IMGFMT + $QEMU_IMG bitmap --add "$TEST_IMG" "good-bitmap" + + $QEMU_IO -c 'write 0 126m' "$TEST_IMG" | _filter_qemu_io + + $QEMU_IMG commit -d "$TEST_IMG" 2>&1 | _filter_generated_node_ids + echo "qemu-img commit exit code: ${PIPESTATUS[0]}" + + $QEMU_IMG bitmap --add "$BASE_JSON" "good-bitmap" + echo "qemu-img bitmap --add exit code: $?" + + $QEMU_IMG bitmap --merge "good-bitmap" -b "$TEST_IMG" "$BASE_JSON" \ + "good-bitmap" 2>&1 | _filter_generated_node_ids + echo "qemu-img bitmap --merge exit code: ${PIPESTATUS[0]}" +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 + diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors.out b/tests/qemu-iotests/tests/qemu-img-close-errors.out new file mode 100644 index 0000000000..1bfe88f176 --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-close-errors.out @@ -0,0 +1,23 @@ +QA output created by qemu-img-close-errors + +=== Test with 6 bitmaps === +wrote 132120576/132120576 bytes at offset 0 +126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Image committed. +qemu-img commit exit code: 0 +qemu-img bitmap --add exit code: 0 +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device +qemu-img: Error while closing the image: Invalid argument +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device +qemu-img bitmap --merge exit code: 1 + +=== Test with 7 bitmaps === +wrote 132120576/132120576 bytes at offset 0 +126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device +qemu-img: Error while closing the image: Invalid argument +qemu-img commit exit code: 1 +qemu-img bitmap --add exit code: 0 +qemu-img bitmap --merge exit code: 0 +*** done From 5b317b8dd95fd5a051f5c84f5442c03fc67faae2 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:41:59 +0100 Subject: [PATCH 322/814] block-coroutine-wrapper: support void functions Just omit the various 'return' when the return type is void. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-2-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- scripts/block-coroutine-wrapper.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index dff3af49f5..e82b648127 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -86,6 +86,16 @@ class FuncDecl: ctx = 'qemu_get_aio_context()' self.ctx = ctx + self.get_result = 's->ret = ' + self.ret = 'return s.ret;' + self.co_ret = 'return ' + self.return_field = self.return_type + " ret;" + if self.return_type == 'void': + self.get_result = '' + self.ret = '' + self.co_ret = '' + self.return_field = '' + def gen_list(self, format: str) -> str: return ', '.join(format.format_map(arg.__dict__) for arg in self.args) @@ -132,7 +142,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: {{ if (qemu_in_coroutine()) {{ {graph_assume_lock} - return {name}({ func.gen_list('{name}') }); + {func.co_ret}{name}({ func.gen_list('{name}') }); }} else {{ {struct_name} s = {{ .poll_state.ctx = {func.ctx}, @@ -144,7 +154,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: s.poll_state.co = qemu_coroutine_create({name}_entry, &s); bdrv_poll_co(&s.poll_state); - return s.ret; + {func.ret} }} }}""" @@ -169,7 +179,7 @@ def create_co_wrapper(func: FuncDecl) -> str: s.poll_state.co = qemu_coroutine_create({name}_entry, &s); bdrv_poll_co(&s.poll_state); - return s.ret; + {func.ret} }}""" @@ -196,7 +206,7 @@ def gen_wrapper(func: FuncDecl) -> str: typedef struct {struct_name} {{ BdrvPollCo poll_state; - {func.return_type} ret; + {func.return_field} { func.gen_block(' {decl};') } }} {struct_name}; @@ -205,7 +215,7 @@ static void coroutine_fn {name}_entry(void *opaque) {struct_name} *s = opaque; {graph_lock} - s->ret = {name}({ func.gen_list('s->{name}') }); + {func.get_result}{name}({ func.gen_list('s->{name}') }); {graph_unlock} s->poll_state.in_progress = false; From 8f4974543203bd1e3a77f198ebb2c60d177b1c40 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:00 +0100 Subject: [PATCH 323/814] block: Convert bdrv_io_plug() to co_wrapper BlockDriver->bdrv_io_plug is categorized as IO callback, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since the callback traverses the block nodes graph, which however is only possible in a coroutine. The only caller of this function is blk_io_plug(), therefore make blk_io_plug() a co_wrapper, so that we're always running in a coroutine where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-3-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block/block-backend.c | 4 ++-- block/file-posix.c | 10 +++++----- block/io.c | 8 ++++---- block/nvme.c | 4 ++-- include/block/block-io.h | 3 ++- include/block/block_int-common.h | 2 +- include/sysemu/block-backend-io.h | 4 +++- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 8fbb787f41..d10998fe19 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2315,13 +2315,13 @@ void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify) notifier_list_add(&blk->insert_bs_notifiers, notify); } -void blk_io_plug(BlockBackend *blk) +void coroutine_fn blk_co_io_plug(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_io_plug(bs); + bdrv_co_io_plug(bs); } } diff --git a/block/file-posix.c b/block/file-posix.c index fa227d9d14..6a5f8d6747 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2132,7 +2132,7 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE); } -static void raw_aio_plug(BlockDriverState *bs) +static void coroutine_fn raw_co_io_plug(BlockDriverState *bs) { BDRVRawState __attribute__((unused)) *s = bs->opaque; #ifdef CONFIG_LINUX_AIO @@ -3317,7 +3317,7 @@ BlockDriver bdrv_file = { .bdrv_co_copy_range_from = raw_co_copy_range_from, .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, + .bdrv_co_io_plug = raw_co_io_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, @@ -3689,7 +3689,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_copy_range_from = raw_co_copy_range_from, .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, + .bdrv_co_io_plug = raw_co_io_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, @@ -3813,7 +3813,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, + .bdrv_co_io_plug = raw_co_io_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, @@ -3943,7 +3943,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, + .bdrv_co_io_plug = raw_co_io_plug, .bdrv_io_unplug = raw_aio_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, diff --git a/block/io.c b/block/io.c index a09a19f7a7..00bab27d34 100644 --- a/block/io.c +++ b/block/io.c @@ -3137,19 +3137,19 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size) return mem; } -void bdrv_io_plug(BlockDriverState *bs) +void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs) { BdrvChild *child; IO_CODE(); QLIST_FOREACH(child, &bs->children, next) { - bdrv_io_plug(child->bs); + bdrv_co_io_plug(child->bs); } if (qatomic_fetch_inc(&bs->io_plugged) == 0) { BlockDriver *drv = bs->drv; - if (drv && drv->bdrv_io_plug) { - drv->bdrv_io_plug(bs); + if (drv && drv->bdrv_co_io_plug) { + drv->bdrv_co_io_plug(bs); } } } diff --git a/block/nvme.c b/block/nvme.c index 1f1367640a..4c32584f07 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1567,7 +1567,7 @@ static void nvme_attach_aio_context(BlockDriverState *bs, } } -static void nvme_aio_plug(BlockDriverState *bs) +static void coroutine_fn nvme_co_io_plug(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; assert(!s->plugged); @@ -1664,7 +1664,7 @@ static BlockDriver bdrv_nvme = { .bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context, - .bdrv_io_plug = nvme_aio_plug, + .bdrv_co_io_plug = nvme_co_io_plug, .bdrv_io_unplug = nvme_aio_unplug, .bdrv_register_buf = nvme_register_buf, diff --git a/include/block/block-io.h b/include/block/block-io.h index 8d571ec2fb..8632fb8533 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -215,7 +215,8 @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); -void bdrv_io_plug(BlockDriverState *bs); +void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs); + void bdrv_io_unplug(BlockDriverState *bs); bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 887ace7dbd..7eea9523da 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -725,7 +725,7 @@ struct BlockDriver { void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); /* io queue for linux-aio */ - void (*bdrv_io_plug)(BlockDriverState *bs); + void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs); void (*bdrv_io_unplug)(BlockDriverState *bs); /** diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 031a27ba10..f3736d1c1b 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -74,7 +74,9 @@ void blk_iostatus_set_err(BlockBackend *blk, int error); int blk_get_max_iov(BlockBackend *blk); int blk_get_max_hw_iov(BlockBackend *blk); -void blk_io_plug(BlockBackend *blk); +void coroutine_fn blk_co_io_plug(BlockBackend *blk); +void co_wrapper blk_io_plug(BlockBackend *blk); + void blk_io_unplug(BlockBackend *blk); AioContext *blk_get_aio_context(BlockBackend *blk); BlockAcctStats *blk_get_stats(BlockBackend *blk); From 09d9fc97f8b0bf30f3c55a5ae3a20f799fd3e5f2 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:01 +0100 Subject: [PATCH 324/814] block: Convert bdrv_io_unplug() to co_wrapper BlockDriver->bdrv_io_unplug is categorized as IO callback, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since the callback traverses the block nodes graph, which however is only possible in a coroutine. The only caller of this function is blk_io_unplug(), therefore make blk_io_unplug() a co_wrapper, so that we're always running in a coroutine where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-4-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block/blkio.c | 4 ++-- block/block-backend.c | 4 ++-- block/file-posix.c | 10 +++++----- block/io.c | 8 ++++---- block/nvme.c | 4 ++-- include/block/block-io.h | 3 +-- include/block/block_int-common.h | 2 +- include/sysemu/block-backend-io.h | 4 +++- 8 files changed, 20 insertions(+), 19 deletions(-) diff --git a/block/blkio.c b/block/blkio.c index 6ad86b23d1..bd53d90d58 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -479,7 +479,7 @@ static int coroutine_fn blkio_co_pwrite_zeroes(BlockDriverState *bs, return cod.ret; } -static void blkio_io_unplug(BlockDriverState *bs) +static void coroutine_fn blkio_co_io_unplug(BlockDriverState *bs) { BDRVBlkioState *s = bs->opaque; @@ -1008,7 +1008,7 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) .bdrv_co_pwritev = blkio_co_pwritev, \ .bdrv_co_flush_to_disk = blkio_co_flush, \ .bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \ - .bdrv_io_unplug = blkio_io_unplug, \ + .bdrv_co_io_unplug = blkio_co_io_unplug, \ .bdrv_refresh_limits = blkio_refresh_limits, \ .bdrv_register_buf = blkio_register_buf, \ .bdrv_unregister_buf = blkio_unregister_buf, \ diff --git a/block/block-backend.c b/block/block-backend.c index d10998fe19..e9cc7d291e 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2325,13 +2325,13 @@ void coroutine_fn blk_co_io_plug(BlockBackend *blk) } } -void blk_io_unplug(BlockBackend *blk) +void coroutine_fn blk_co_io_unplug(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_io_unplug(bs); + bdrv_co_io_unplug(bs); } } diff --git a/block/file-posix.c b/block/file-posix.c index 6a5f8d6747..3b112095a4 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2149,7 +2149,7 @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs) #endif } -static void raw_aio_unplug(BlockDriverState *bs) +static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs) { BDRVRawState __attribute__((unused)) *s = bs->opaque; #ifdef CONFIG_LINUX_AIO @@ -3318,7 +3318,7 @@ BlockDriver bdrv_file = { .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, .bdrv_co_io_plug = raw_co_io_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, .bdrv_co_truncate = raw_co_truncate, @@ -3690,7 +3690,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, .bdrv_co_io_plug = raw_co_io_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, .bdrv_co_truncate = raw_co_truncate, @@ -3814,7 +3814,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, .bdrv_co_io_plug = raw_co_io_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, .bdrv_co_truncate = raw_co_truncate, @@ -3944,7 +3944,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, .bdrv_co_io_plug = raw_co_io_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, .bdrv_co_truncate = raw_co_truncate, diff --git a/block/io.c b/block/io.c index 00bab27d34..d988053e4e 100644 --- a/block/io.c +++ b/block/io.c @@ -3154,7 +3154,7 @@ void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs) } } -void bdrv_io_unplug(BlockDriverState *bs) +void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs) { BdrvChild *child; IO_CODE(); @@ -3162,13 +3162,13 @@ void bdrv_io_unplug(BlockDriverState *bs) assert(bs->io_plugged); if (qatomic_fetch_dec(&bs->io_plugged) == 1) { BlockDriver *drv = bs->drv; - if (drv && drv->bdrv_io_unplug) { - drv->bdrv_io_unplug(bs); + if (drv && drv->bdrv_co_io_unplug) { + drv->bdrv_co_io_unplug(bs); } } QLIST_FOREACH(child, &bs->children, next) { - bdrv_io_unplug(child->bs); + bdrv_co_io_unplug(child->bs); } } diff --git a/block/nvme.c b/block/nvme.c index 4c32584f07..1fe6f98925 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1574,7 +1574,7 @@ static void coroutine_fn nvme_co_io_plug(BlockDriverState *bs) s->plugged = true; } -static void nvme_aio_unplug(BlockDriverState *bs) +static void coroutine_fn nvme_co_io_unplug(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; assert(s->plugged); @@ -1665,7 +1665,7 @@ static BlockDriver bdrv_nvme = { .bdrv_attach_aio_context = nvme_attach_aio_context, .bdrv_co_io_plug = nvme_co_io_plug, - .bdrv_io_unplug = nvme_aio_unplug, + .bdrv_co_io_unplug = nvme_co_io_unplug, .bdrv_register_buf = nvme_register_buf, .bdrv_unregister_buf = nvme_unregister_buf, diff --git a/include/block/block-io.h b/include/block/block-io.h index 8632fb8533..d7fd2723f2 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -216,8 +216,7 @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs); - -void bdrv_io_unplug(BlockDriverState *bs); +void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs); bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 7eea9523da..b71fa04cc4 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -726,7 +726,7 @@ struct BlockDriver { /* io queue for linux-aio */ void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs); - void (*bdrv_io_unplug)(BlockDriverState *bs); + void coroutine_fn (*bdrv_co_io_unplug)(BlockDriverState *bs); /** * bdrv_drain_begin is called if implemented in the beginning of a diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index f3736d1c1b..0d432cc1f9 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -77,7 +77,9 @@ int blk_get_max_hw_iov(BlockBackend *blk); void coroutine_fn blk_co_io_plug(BlockBackend *blk); void co_wrapper blk_io_plug(BlockBackend *blk); -void blk_io_unplug(BlockBackend *blk); +void coroutine_fn blk_co_io_unplug(BlockBackend *blk); +void co_wrapper blk_io_unplug(BlockBackend *blk); + AioContext *blk_get_aio_context(BlockBackend *blk); BlockAcctStats *blk_get_stats(BlockBackend *blk); void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, From 1e97be915697fff198e9922321066cf9b44ef4b9 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:02 +0100 Subject: [PATCH 325/814] block: Convert bdrv_is_inserted() to co_wrapper bdrv_is_inserted() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. Therefore turn it into a co_wrapper to move the actual function into a coroutine where the lock can be taken. At the same time, add also blk_is_inserted as co_wrapper_mixed, since it is called in both coroutine and non-coroutine contexts. Because now this function creates a new coroutine and polls, we need to take the AioContext lock where it is missing, for the only reason that internally c_w_mixed_bdrv_rdlock calls AIO_WAIT_WHILE and it expects to release the AioContext lock. Once the rwlock is ultimated and placed in every place it needs to be, we will poll using AIO_WAIT_WHILE_UNLOCKED and remove the AioContext lock. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-5-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 8 ++++---- block/block-backend.c | 4 ++-- block/file-posix.c | 8 ++++---- block/io.c | 12 ++++++------ blockdev.c | 8 +++++++- include/block/block-io.h | 5 ++++- include/block/block_int-common.h | 2 +- include/sysemu/block-backend-io.h | 5 ++++- 8 files changed, 32 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index ad92fdf1b3..ab360e8cd6 100644 --- a/block.c +++ b/block.c @@ -6782,7 +6782,7 @@ out: /** * Return TRUE if the media is present */ -bool bdrv_is_inserted(BlockDriverState *bs) +bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs) { BlockDriver *drv = bs->drv; BdrvChild *child; @@ -6791,11 +6791,11 @@ bool bdrv_is_inserted(BlockDriverState *bs) if (!drv) { return false; } - if (drv->bdrv_is_inserted) { - return drv->bdrv_is_inserted(bs); + if (drv->bdrv_co_is_inserted) { + return drv->bdrv_co_is_inserted(bs); } QLIST_FOREACH(child, &bs->children, next) { - if (!bdrv_is_inserted(child->bs)) { + if (!bdrv_co_is_inserted(child->bs)) { return false; } } diff --git a/block/block-backend.c b/block/block-backend.c index e9cc7d291e..7ba436811b 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1983,12 +1983,12 @@ void blk_activate(BlockBackend *blk, Error **errp) bdrv_activate(bs, errp); } -bool blk_is_inserted(BlockBackend *blk) +bool coroutine_fn blk_co_is_inserted(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); - return bs && bdrv_is_inserted(bs); + return bs && bdrv_co_is_inserted(bs); } bool blk_is_available(BlockBackend *blk) diff --git a/block/file-posix.c b/block/file-posix.c index 3b112095a4..433a25fc91 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3757,7 +3757,7 @@ out: return prio; } -static bool cdrom_is_inserted(BlockDriverState *bs) +static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int ret; @@ -3824,7 +3824,7 @@ static BlockDriver bdrv_host_cdrom = { = raw_get_allocated_file_size, /* removable device support */ - .bdrv_is_inserted = cdrom_is_inserted, + .bdrv_co_is_inserted = cdrom_co_is_inserted, .bdrv_eject = cdrom_eject, .bdrv_lock_medium = cdrom_lock_medium, @@ -3883,7 +3883,7 @@ static int cdrom_reopen(BlockDriverState *bs) return 0; } -static bool cdrom_is_inserted(BlockDriverState *bs) +static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) { return raw_getlength(bs) > 0; } @@ -3954,7 +3954,7 @@ static BlockDriver bdrv_host_cdrom = { = raw_get_allocated_file_size, /* removable device support */ - .bdrv_is_inserted = cdrom_is_inserted, + .bdrv_co_is_inserted = cdrom_co_is_inserted, .bdrv_eject = cdrom_eject, .bdrv_lock_medium = cdrom_lock_medium, }; diff --git a/block/io.c b/block/io.c index d988053e4e..1093b8d4b9 100644 --- a/block/io.c +++ b/block/io.c @@ -1622,7 +1622,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, trace_bdrv_co_preadv_part(bs, offset, bytes, flags); - if (!bdrv_is_inserted(bs)) { + if (!bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -2067,7 +2067,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags); - if (!bdrv_is_inserted(bs)) { + if (!bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -2835,7 +2835,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) bdrv_inc_in_flight(bs); - if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs) || + if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs) || bdrv_is_sg(bs)) { goto early_exit; } @@ -2959,7 +2959,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, BlockDriverState *bs = child->bs; IO_CODE(); - if (!bs || !bs->drv || !bdrv_is_inserted(bs)) { + if (!bs || !bs->drv || !bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -3241,7 +3241,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( assert(!(read_flags & BDRV_REQ_NO_WAIT)); assert(!(write_flags & BDRV_REQ_NO_WAIT)); - if (!dst || !dst->bs || !bdrv_is_inserted(dst->bs)) { + if (!dst || !dst->bs || !bdrv_co_is_inserted(dst->bs)) { return -ENOMEDIUM; } ret = bdrv_check_request32(dst_offset, bytes, NULL, 0); @@ -3252,7 +3252,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, write_flags); } - if (!src || !src->bs || !bdrv_is_inserted(src->bs)) { + if (!src || !src->bs || !bdrv_co_is_inserted(src->bs)) { return -ENOMEDIUM; } ret = bdrv_check_request32(src_offset, bytes, NULL, 0); diff --git a/blockdev.c b/blockdev.c index fe9d8d89c0..d7b5c18f0a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1024,6 +1024,7 @@ fail: static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) { BlockDriverState *bs; + AioContext *aio_context; bs = bdrv_lookup_bs(name, name, errp); if (bs == NULL) { @@ -1035,11 +1036,16 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) return NULL; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + if (!bdrv_is_inserted(bs)) { error_setg(errp, "Device has no medium"); - return NULL; + bs = NULL; } + aio_context_release(aio_context); + return bs; } diff --git a/include/block/block-io.h b/include/block/block-io.h index d7fd2723f2..f27d935982 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -136,7 +136,10 @@ bool bdrv_is_read_only(BlockDriverState *bs); bool bdrv_is_writable(BlockDriverState *bs); bool bdrv_is_sg(BlockDriverState *bs); int bdrv_get_flags(BlockDriverState *bs); -bool bdrv_is_inserted(BlockDriverState *bs); + +bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs); +bool co_wrapper bdrv_is_inserted(BlockDriverState *bs); + void bdrv_lock_medium(BlockDriverState *bs, bool locked); void bdrv_eject(BlockDriverState *bs, bool eject_flag); const char *bdrv_get_format_name(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index b71fa04cc4..9ec68f515c 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -704,7 +704,7 @@ struct BlockDriver { BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); /* removable device specific */ - bool (*bdrv_is_inserted)(BlockDriverState *bs); + bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs); void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 0d432cc1f9..7cc96a56c7 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -54,7 +54,10 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, void blk_inc_in_flight(BlockBackend *blk); void blk_dec_in_flight(BlockBackend *blk); -bool blk_is_inserted(BlockBackend *blk); + +bool coroutine_fn blk_co_is_inserted(BlockBackend *blk); +bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); + bool blk_is_available(BlockBackend *blk); void blk_lock_medium(BlockBackend *blk, bool locked); void blk_eject(BlockBackend *blk, bool eject_flag); From c057960c4e33becb22d4741156203a4b0d4a3088 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:03 +0100 Subject: [PATCH 326/814] block: Rename refresh_total_sectors to bdrv_refresh_total_sectors The name is not good, not the least because we are going to convert this to a generated co_wrapper, which adds a _co infix after the first part of the name. No functional change intended. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-6-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 8 ++++---- block/io.c | 8 +++++--- include/block/block_int-io.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index ab360e8cd6..b6c6b17cb2 100644 --- a/block.c +++ b/block.c @@ -1035,7 +1035,7 @@ static int find_image_format(BlockBackend *file, const char *filename, * Set the current 'total_sectors' value * Return 0 on success, -errno on error. */ -int refresh_total_sectors(BlockDriverState *bs, int64_t hint) +int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -1652,7 +1652,7 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF; bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF; - ret = refresh_total_sectors(bs, bs->total_sectors); + ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); return ret; @@ -5809,7 +5809,7 @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) return -ENOMEDIUM; if (drv->has_variable_length) { - int ret = refresh_total_sectors(bs, bs->total_sectors); + int ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { return ret; } @@ -6591,7 +6591,7 @@ int bdrv_activate(BlockDriverState *bs, Error **errp) bdrv_dirty_bitmap_skip_store(bm, false); } - ret = refresh_total_sectors(bs, bs->total_sectors); + ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { bs->open_flags |= BDRV_O_INACTIVE; error_setg_errno(errp, -ret, "Could not refresh total sector count"); diff --git a/block/io.c b/block/io.c index 1093b8d4b9..d78ad87e3c 100644 --- a/block/io.c +++ b/block/io.c @@ -3474,15 +3474,17 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, goto out; } - ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); + ret = bdrv_refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); } else { offset = bs->total_sectors * BDRV_SECTOR_SIZE; } - /* It's possible that truncation succeeded but refresh_total_sectors + /* + * It's possible that truncation succeeded but bdrv_refresh_total_sectors * failed, but the latter doesn't affect how we should finish the request. - * Pass 0 as the last parameter so that dirty bitmaps etc. are handled. */ + * Pass 0 as the last parameter so that dirty bitmaps etc. are handled. + */ bdrv_co_write_req_finish(child, offset - new_bytes, new_bytes, &req, 0); out: diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 44367219f4..37b0fd974b 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -122,7 +122,7 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); -int refresh_total_sectors(BlockDriverState *bs, int64_t hint); +int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); BdrvChild *bdrv_cow_child(BlockDriverState *bs); BdrvChild *bdrv_filter_child(BlockDriverState *bs); From c86422c5549c0983b4b4525b8f56a1c69dd67aa1 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:04 +0100 Subject: [PATCH 327/814] block: Convert bdrv_refresh_total_sectors() to co_wrapper_mixed BlockDriver->bdrv_getlength is categorized as IO callback, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since the callback traverses the block nodes graph, which however is only possible in a coroutine. Therefore turn it into a co_wrapper to move the actual function into a coroutine where the lock can be taken. Because now this function creates a new coroutine and polls, we need to take the AioContext lock where it is missing, for the only reason that internally co_wrapper calls AIO_WAIT_WHILE and it expects to release the AioContext lock. This is especially messy when a co_wrapper creates a coroutine and polls in bdrv_open_driver, because this function has so many callers in so many context that it can easily lead to deadlocks. Therefore the new rule for bdrv_open_driver is that the caller must always hold the AioContext lock of the given bs (except if it is a coroutine), because the function calls bdrv_refresh_total_sectors() which is now a co_wrapper. Once the rwlock is ultimated and placed in every place it needs to be, we will poll using AIO_WAIT_WHILE_UNLOCKED and remove the AioContext lock. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-7-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 32 +++++++++++++++++------ block/blkdebug.c | 6 ++--- block/blkio.c | 6 ++--- block/blklogwrites.c | 6 ++--- block/blkreplay.c | 6 ++--- block/blkverify.c | 6 ++--- block/block-backend.c | 10 +++++--- block/commit.c | 4 +-- block/copy-on-read.c | 6 ++--- block/crypto.c | 6 ++--- block/curl.c | 10 ++++---- block/file-posix.c | 42 +++++++++++++++---------------- block/file-win32.c | 8 +++--- block/filter-compress.c | 6 ++--- block/gluster.c | 12 ++++----- block/iscsi.c | 10 ++++---- block/meson.build | 1 + block/mirror.c | 4 +-- block/nbd.c | 8 +++--- block/null.c | 6 ++--- block/nvme.c | 6 ++--- block/preallocate.c | 10 ++++---- block/qed.c | 4 +-- block/quorum.c | 8 +++--- block/raw-format.c | 6 ++--- block/rbd.c | 4 +-- block/replication.c | 6 ++--- block/ssh.c | 4 +-- block/throttle.c | 6 ++--- hw/scsi/scsi-disk.c | 5 ++++ include/block/block-io.h | 8 ++++-- include/block/block_int-common.h | 2 +- include/block/block_int-io.h | 5 +++- include/sysemu/block-backend-io.h | 10 ++++++-- tests/unit/test-block-iothread.c | 3 +++ 35 files changed, 161 insertions(+), 121 deletions(-) diff --git a/block.c b/block.c index b6c6b17cb2..ee6f90990e 100644 --- a/block.c +++ b/block.c @@ -1035,7 +1035,8 @@ static int find_image_format(BlockBackend *file, const char *filename, * Set the current 'total_sectors' value * Return 0 on success, -errno on error. */ -int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint) +int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, + int64_t hint) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -1044,13 +1045,13 @@ int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint) return -ENOMEDIUM; } - /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */ + /* Do not attempt drv->bdrv_co_getlength() on scsi-generic devices */ if (bdrv_is_sg(bs)) return 0; /* query actual device if possible, otherwise just trust the hint */ - if (drv->bdrv_getlength) { - int64_t length = drv->bdrv_getlength(bs); + if (drv->bdrv_co_getlength) { + int64_t length = drv->bdrv_co_getlength(bs); if (length < 0) { return length; } @@ -1601,6 +1602,11 @@ out: g_free(gen_node_name); } +/* + * The caller must always hold @bs AioContext lock, because this function calls + * bdrv_refresh_total_sectors() which polls when called from non-coroutine + * context. + */ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name, QDict *options, int open_flags, Error **errp) @@ -3796,6 +3802,10 @@ out: * The reference parameter may be used to specify an existing block device which * should be opened. If specified, neither options nor a filename may be given, * nor can an existing BDS be reused (that is, *pbs has to be NULL). + * + * The caller must always hold @filename AioContext lock, because this + * function eventually calls bdrv_refresh_total_sectors() which polls + * when called from non-coroutine context. */ static BlockDriverState *bdrv_open_inherit(const char *filename, const char *reference, @@ -4084,6 +4094,11 @@ close_and_fail: return NULL; } +/* + * The caller must always hold @filename AioContext lock, because this + * function eventually calls bdrv_refresh_total_sectors() which polls + * when called from non-coroutine context. + */ BlockDriverState *bdrv_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp) { @@ -5800,7 +5815,7 @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, /** * Return number of sectors on success, -errno on error. */ -int64_t bdrv_nb_sectors(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -5809,7 +5824,7 @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) return -ENOMEDIUM; if (drv->has_variable_length) { - int ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); + int ret = bdrv_co_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { return ret; } @@ -5821,11 +5836,12 @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) * Return length in bytes on success, -errno on error. * The length is always a multiple of BDRV_SECTOR_SIZE. */ -int64_t bdrv_getlength(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs) { - int64_t ret = bdrv_nb_sectors(bs); + int64_t ret; IO_CODE(); + ret = bdrv_co_nb_sectors(bs); if (ret < 0) { return ret; } diff --git a/block/blkdebug.c b/block/blkdebug.c index fa38c1cf7d..e6dc0ba142 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -966,9 +966,9 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) return false; } -static int64_t blkdebug_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkdebug_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static void blkdebug_refresh_filename(BlockDriverState *bs) @@ -1075,7 +1075,7 @@ static BlockDriver bdrv_blkdebug = { .bdrv_reopen_prepare = blkdebug_reopen_prepare, .bdrv_child_perm = blkdebug_child_perm, - .bdrv_getlength = blkdebug_getlength, + .bdrv_co_getlength = blkdebug_co_getlength, .bdrv_refresh_filename = blkdebug_refresh_filename, .bdrv_refresh_limits = blkdebug_refresh_limits, diff --git a/block/blkio.c b/block/blkio.c index bd53d90d58..284fb292cf 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -839,7 +839,7 @@ static void blkio_close(BlockDriverState *bs) } } -static int64_t blkio_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkio_co_getlength(BlockDriverState *bs) { BDRVBlkioState *s = bs->opaque; uint64_t capacity; @@ -867,7 +867,7 @@ static int coroutine_fn blkio_truncate(BlockDriverState *bs, int64_t offset, return -ENOTSUP; } - current_length = blkio_getlength(bs); + current_length = blkio_co_getlength(bs); if (offset > current_length) { error_setg(errp, "Cannot grow device"); @@ -998,7 +998,7 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) .instance_size = sizeof(BDRVBlkioState), \ .bdrv_file_open = blkio_file_open, \ .bdrv_close = blkio_close, \ - .bdrv_getlength = blkio_getlength, \ + .bdrv_co_getlength = blkio_co_getlength, \ .bdrv_co_truncate = blkio_truncate, \ .bdrv_get_info = blkio_get_info, \ .bdrv_attach_aio_context = blkio_attach_aio_context, \ diff --git a/block/blklogwrites.c b/block/blklogwrites.c index a5bf767184..b00b8a6dd0 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -267,9 +267,9 @@ static void blk_log_writes_close(BlockDriverState *bs) s->log_file = NULL; } -static int64_t blk_log_writes_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blk_log_writes_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, @@ -498,7 +498,7 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_open = blk_log_writes_open, .bdrv_close = blk_log_writes_close, - .bdrv_getlength = blk_log_writes_getlength, + .bdrv_co_getlength = blk_log_writes_co_getlength, .bdrv_child_perm = blk_log_writes_child_perm, .bdrv_refresh_limits = blk_log_writes_refresh_limits, diff --git a/block/blkreplay.c b/block/blkreplay.c index e3b6a3efb2..16543f585a 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -40,9 +40,9 @@ fail: return ret; } -static int64_t blkreplay_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkreplay_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } /* This bh is used for synchronization of return from coroutines. @@ -136,7 +136,7 @@ static BlockDriver bdrv_blkreplay = { .bdrv_open = blkreplay_open, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = blkreplay_getlength, + .bdrv_co_getlength = blkreplay_co_getlength, .bdrv_co_preadv = blkreplay_co_preadv, .bdrv_co_pwritev = blkreplay_co_pwritev, diff --git a/block/blkverify.c b/block/blkverify.c index 0e78bc9dd6..edf1a550f2 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -155,11 +155,11 @@ static void blkverify_close(BlockDriverState *bs) s->test_file = NULL; } -static int64_t blkverify_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkverify_co_getlength(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - return bdrv_getlength(s->test_file->bs); + return bdrv_co_getlength(s->test_file->bs); } static void coroutine_fn blkverify_do_test_req(void *opaque) @@ -314,7 +314,7 @@ static BlockDriver bdrv_blkverify = { .bdrv_file_open = blkverify_open, .bdrv_close = blkverify_close, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = blkverify_getlength, + .bdrv_co_getlength = blkverify_co_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, .bdrv_dirname = blkverify_dirname, diff --git a/block/block-backend.c b/block/block-backend.c index 7ba436811b..d698cc3f33 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1599,14 +1599,15 @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, flags | BDRV_REQ_ZERO_WRITE, cb, opaque); } -int64_t blk_getlength(BlockBackend *blk) +int64_t coroutine_fn blk_co_getlength(BlockBackend *blk) { IO_CODE(); + if (!blk_is_available(blk)) { return -ENOMEDIUM; } - return bdrv_getlength(blk_bs(blk)); + return bdrv_co_getlength(blk_bs(blk)); } void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) @@ -1619,14 +1620,15 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) } } -int64_t blk_nb_sectors(BlockBackend *blk) +int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk) { IO_CODE(); + if (!blk_is_available(blk)) { return -ENOMEDIUM; } - return bdrv_nb_sectors(blk_bs(blk)); + return bdrv_co_nb_sectors(blk_bs(blk)); } BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, diff --git a/block/commit.c b/block/commit.c index b346341767..41e3599281 100644 --- a/block/commit.c +++ b/block/commit.c @@ -123,13 +123,13 @@ static int coroutine_fn commit_run(Job *job, Error **errp) QEMU_AUTO_VFREE void *buf = NULL; int64_t len, base_len; - len = blk_getlength(s->top); + len = blk_co_getlength(s->top); if (len < 0) { return len; } job_progress_set_remaining(&s->common.job, len); - base_len = blk_getlength(s->base); + base_len = blk_co_getlength(s->base); if (base_len < 0) { return base_len; } diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 13ed4150a6..8cad979e29 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -121,9 +121,9 @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, } -static int64_t cor_getlength(BlockDriverState *bs) +static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } @@ -250,7 +250,7 @@ static BlockDriver bdrv_copy_on_read = { .bdrv_close = cor_close, .bdrv_child_perm = cor_child_perm, - .bdrv_getlength = cor_getlength, + .bdrv_co_getlength = cor_co_getlength, .bdrv_co_preadv_part = cor_co_preadv_part, .bdrv_co_pwritev_part = cor_co_pwritev_part, diff --git a/block/crypto.c b/block/crypto.c index bbeb9f437c..6d6c006887 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -531,10 +531,10 @@ static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp) } -static int64_t block_crypto_getlength(BlockDriverState *bs) +static int64_t coroutine_fn block_crypto_co_getlength(BlockDriverState *bs) { BlockCrypto *crypto = bs->opaque; - int64_t len = bdrv_getlength(bs->file->bs); + int64_t len = bdrv_co_getlength(bs->file->bs); uint64_t offset = qcrypto_block_get_payload_offset(crypto->block); assert(offset < INT64_MAX); @@ -953,7 +953,7 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_refresh_limits = block_crypto_refresh_limits, .bdrv_co_preadv = block_crypto_co_preadv, .bdrv_co_pwritev = block_crypto_co_pwritev, - .bdrv_getlength = block_crypto_getlength, + .bdrv_co_getlength = block_crypto_co_getlength, .bdrv_measure = block_crypto_measure, .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, diff --git a/block/curl.c b/block/curl.c index bf45fa3244..cbada22e9e 100644 --- a/block/curl.c +++ b/block/curl.c @@ -958,7 +958,7 @@ static void curl_close(BlockDriverState *bs) g_free(s->proxypassword); } -static int64_t curl_getlength(BlockDriverState *bs) +static int64_t coroutine_fn curl_co_getlength(BlockDriverState *bs) { BDRVCURLState *s = bs->opaque; return s->len; @@ -1002,7 +1002,7 @@ static BlockDriver bdrv_http = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1021,7 +1021,7 @@ static BlockDriver bdrv_https = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1040,7 +1040,7 @@ static BlockDriver bdrv_ftp = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1059,7 +1059,7 @@ static BlockDriver bdrv_ftps = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, diff --git a/block/file-posix.c b/block/file-posix.c index 433a25fc91..b8a42601e9 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -189,7 +189,7 @@ static int fd_open(BlockDriverState *bs) return -EIO; } -static int64_t raw_getlength(BlockDriverState *bs); +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs); typedef struct RawPosixAIOData { BlockDriverState *bs; @@ -2280,7 +2280,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, } if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { - int64_t cur_length = raw_getlength(bs); + int64_t cur_length = raw_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize device files"); @@ -2298,7 +2298,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, } #ifdef __OpenBSD__ -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2317,7 +2317,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return st.st_size; } #elif defined(__NetBSD__) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2342,7 +2342,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return st.st_size; } #elif defined(__sun__) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; struct dk_minfo minfo; @@ -2373,7 +2373,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return size; } #elif defined(CONFIG_BSD) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2445,7 +2445,7 @@ again: return size; } #else -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int ret; @@ -2830,7 +2830,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, * round up if necessary. */ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) { - int64_t file_length = raw_getlength(bs); + int64_t file_length = raw_co_getlength(bs); if (file_length > 0) { /* Ignore errors, this is just a safeguard */ assert(hole == file_length); @@ -2852,7 +2852,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, #if defined(__linux__) /* Verify that the file is not in the page cache */ -static void check_cache_dropped(BlockDriverState *bs, Error **errp) +static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp) { const size_t window_size = 128 * 1024 * 1024; BDRVRawState *s = bs->opaque; @@ -2867,7 +2867,7 @@ static void check_cache_dropped(BlockDriverState *bs, Error **errp) page_size = sysconf(_SC_PAGESIZE); vec = g_malloc(DIV_ROUND_UP(window_size, page_size)); - end = raw_getlength(bs); + end = raw_co_getlength(bs); for (offset = 0; offset < end; offset += window_size) { void *new_window; @@ -3321,8 +3321,8 @@ BlockDriver bdrv_file = { .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, .bdrv_get_info = raw_get_info, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, @@ -3693,8 +3693,8 @@ static BlockDriver bdrv_host_device = { .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, .bdrv_get_info = raw_get_info, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, @@ -3817,9 +3817,9 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, @@ -3885,7 +3885,7 @@ static int cdrom_reopen(BlockDriverState *bs) static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) { - return raw_getlength(bs) > 0; + return raw_co_getlength(bs) > 0; } static void cdrom_eject(BlockDriverState *bs, bool eject_flag) @@ -3947,9 +3947,9 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, diff --git a/block/file-win32.c b/block/file-win32.c index 12be9c3d0f..61a3aa27a7 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -526,7 +526,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; @@ -764,7 +764,7 @@ BlockDriver bdrv_file = { .bdrv_aio_flush = raw_aio_flush, .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, + .bdrv_co_getlength = raw_co_getlength, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, @@ -933,8 +933,8 @@ static BlockDriver bdrv_host_device = { .bdrv_detach_aio_context = raw_detach_aio_context, .bdrv_attach_aio_context = raw_attach_aio_context, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, .bdrv_get_allocated_file_size = raw_get_allocated_file_size, diff --git a/block/filter-compress.c b/block/filter-compress.c index 0ff8d28661..bcf76ac910 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -55,9 +55,9 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, } -static int64_t compress_getlength(BlockDriverState *bs) +static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } @@ -135,7 +135,7 @@ static BlockDriver bdrv_compress = { .bdrv_open = compress_open, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = compress_getlength, + .bdrv_co_getlength = compress_co_getlength, .bdrv_co_preadv_part = compress_co_preadv_part, .bdrv_co_pwritev_part = compress_co_pwritev_part, diff --git a/block/gluster.c b/block/gluster.c index 1ad19ae915..0b325e4292 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1318,7 +1318,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs, } #endif -static int64_t qemu_gluster_getlength(BlockDriverState *bs) +static int64_t coroutine_fn qemu_gluster_co_getlength(BlockDriverState *bs) { BDRVGlusterState *s = bs->opaque; int64_t ret; @@ -1510,7 +1510,7 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, * round up if necessary. */ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) { - int64_t file_length = qemu_gluster_getlength(bs); + int64_t file_length = qemu_gluster_co_getlength(bs); if (file_length > 0) { /* Ignore errors, this is just a safeguard */ assert(hole == file_length); @@ -1559,7 +1559,7 @@ static BlockDriver bdrv_gluster = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, - .bdrv_getlength = qemu_gluster_getlength, + .bdrv_co_getlength = qemu_gluster_co_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, @@ -1588,7 +1588,7 @@ static BlockDriver bdrv_gluster_tcp = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, - .bdrv_getlength = qemu_gluster_getlength, + .bdrv_co_getlength = qemu_gluster_co_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, @@ -1617,7 +1617,7 @@ static BlockDriver bdrv_gluster_unix = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, - .bdrv_getlength = qemu_gluster_getlength, + .bdrv_co_getlength = qemu_gluster_co_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, @@ -1652,7 +1652,7 @@ static BlockDriver bdrv_gluster_rdma = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, - .bdrv_getlength = qemu_gluster_getlength, + .bdrv_co_getlength = qemu_gluster_co_getlength, .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, diff --git a/block/iscsi.c b/block/iscsi.c index c16c592042..359b532a33 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1127,8 +1127,8 @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, #endif -static int64_t -iscsi_getlength(BlockDriverState *bs) +static int64_t coroutine_fn +iscsi_co_getlength(BlockDriverState *bs) { IscsiLun *iscsilun = bs->opaque; int64_t len; @@ -2155,7 +2155,7 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, return -EIO; } - cur_length = iscsi_getlength(bs); + cur_length = iscsi_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize iSCSI devices"); return -ENOTSUP; @@ -2434,7 +2434,7 @@ static BlockDriver bdrv_iscsi = { .bdrv_reopen_commit = iscsi_reopen_commit, .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, - .bdrv_getlength = iscsi_getlength, + .bdrv_co_getlength = iscsi_co_getlength, .bdrv_get_info = iscsi_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, @@ -2473,7 +2473,7 @@ static BlockDriver bdrv_iser = { .bdrv_reopen_commit = iscsi_reopen_commit, .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, - .bdrv_getlength = iscsi_getlength, + .bdrv_co_getlength = iscsi_co_getlength, .bdrv_get_info = iscsi_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, diff --git a/block/meson.build b/block/meson.build index 90011a2805..3662852dc2 100644 --- a/block/meson.build +++ b/block/meson.build @@ -139,6 +139,7 @@ block_gen_c = custom_target('block-gen.c', input: files( '../include/block/block-io.h', '../include/block/dirty-bitmap.h', + '../include/block/block_int-io.h', '../include/block/block-global-state.h', '../include/sysemu/block-backend-io.h', 'coroutines.h' diff --git a/block/mirror.c b/block/mirror.c index 634815d78d..7ed4dbde04 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -910,13 +910,13 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) goto immediate_exit; } - s->bdev_length = bdrv_getlength(bs); + s->bdev_length = bdrv_co_getlength(bs); if (s->bdev_length < 0) { ret = s->bdev_length; goto immediate_exit; } - target_length = blk_getlength(s->target); + target_length = blk_co_getlength(s->target); if (target_length < 0) { ret = target_length; goto immediate_exit; diff --git a/block/nbd.c b/block/nbd.c index 7d485c86d2..bf2894ad5c 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1992,7 +1992,7 @@ static int coroutine_fn nbd_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int64_t nbd_getlength(BlockDriverState *bs) +static int64_t coroutine_fn nbd_co_getlength(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; @@ -2124,7 +2124,7 @@ static BlockDriver bdrv_nbd = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, @@ -2152,7 +2152,7 @@ static BlockDriver bdrv_nbd_tcp = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, @@ -2180,7 +2180,7 @@ static BlockDriver bdrv_nbd_unix = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, diff --git a/block/null.c b/block/null.c index 306e605fa1..bc4d0c1d9d 100644 --- a/block/null.c +++ b/block/null.c @@ -100,7 +100,7 @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags, return ret; } -static int64_t null_getlength(BlockDriverState *bs) +static int64_t coroutine_fn null_co_getlength(BlockDriverState *bs) { BDRVNullState *s = bs->opaque; return s->length; @@ -284,7 +284,7 @@ static BlockDriver bdrv_null_co = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_co_parse_filename, - .bdrv_getlength = null_getlength, + .bdrv_co_getlength = null_co_getlength, .bdrv_get_allocated_file_size = null_allocated_file_size, .bdrv_co_preadv = null_co_preadv, @@ -305,7 +305,7 @@ static BlockDriver bdrv_null_aio = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_aio_parse_filename, - .bdrv_getlength = null_getlength, + .bdrv_co_getlength = null_co_getlength, .bdrv_get_allocated_file_size = null_allocated_file_size, .bdrv_aio_preadv = null_aio_preadv, diff --git a/block/nvme.c b/block/nvme.c index 1fe6f98925..5b744c2bda 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1002,7 +1002,7 @@ fail: return ret; } -static int64_t nvme_getlength(BlockDriverState *bs) +static int64_t coroutine_fn nvme_co_getlength(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; return s->nsze << s->blkshift; @@ -1486,7 +1486,7 @@ static int coroutine_fn nvme_co_truncate(BlockDriverState *bs, int64_t offset, return -ENOTSUP; } - cur_length = nvme_getlength(bs); + cur_length = nvme_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize NVMe devices"); return -ENOTSUP; @@ -1643,7 +1643,7 @@ static BlockDriver bdrv_nvme = { .bdrv_parse_filename = nvme_parse_filename, .bdrv_file_open = nvme_file_open, .bdrv_close = nvme_close, - .bdrv_getlength = nvme_getlength, + .bdrv_co_getlength = nvme_co_getlength, .bdrv_probe_blocksizes = nvme_probe_blocksizes, .bdrv_co_truncate = nvme_co_truncate, diff --git a/block/preallocate.c b/block/preallocate.c index a51fc08515..c9881942a3 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -442,7 +442,7 @@ static int coroutine_fn preallocate_co_flush(BlockDriverState *bs) return bdrv_co_flush(bs->file->bs); } -static int64_t preallocate_getlength(BlockDriverState *bs) +static int64_t coroutine_fn preallocate_co_getlength(BlockDriverState *bs) { int64_t ret; BDRVPreallocateState *s = bs->opaque; @@ -451,7 +451,7 @@ static int64_t preallocate_getlength(BlockDriverState *bs) return s->data_end; } - ret = bdrv_getlength(bs->file->bs); + ret = bdrv_co_getlength(bs->file->bs); if (has_prealloc_perms(bs)) { s->file_end = s->zero_start = s->data_end = ret; @@ -537,9 +537,9 @@ BlockDriver bdrv_preallocate_filter = { .format_name = "preallocate", .instance_size = sizeof(BDRVPreallocateState), - .bdrv_getlength = preallocate_getlength, - .bdrv_open = preallocate_open, - .bdrv_close = preallocate_close, + .bdrv_co_getlength = preallocate_co_getlength, + .bdrv_open = preallocate_open, + .bdrv_close = preallocate_close, .bdrv_reopen_prepare = preallocate_reopen_prepare, .bdrv_reopen_commit = preallocate_reopen_commit, diff --git a/block/qed.c b/block/qed.c index faa606618e..c8f9045b72 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1480,7 +1480,7 @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs, return ret; } -static int64_t bdrv_qed_getlength(BlockDriverState *bs) +static int64_t coroutine_fn bdrv_qed_co_getlength(BlockDriverState *bs) { BDRVQEDState *s = bs->opaque; return s->header.image_size; @@ -1653,7 +1653,7 @@ static BlockDriver bdrv_qed = { .bdrv_co_writev = bdrv_qed_co_writev, .bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes, .bdrv_co_truncate = bdrv_qed_co_truncate, - .bdrv_getlength = bdrv_qed_getlength, + .bdrv_co_getlength = bdrv_qed_co_getlength, .bdrv_get_info = bdrv_qed_get_info, .bdrv_refresh_limits = bdrv_qed_refresh_limits, .bdrv_change_backing_file = bdrv_qed_change_backing_file, diff --git a/block/quorum.c b/block/quorum.c index 7f21c03f1f..d1dcf2eaba 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -754,19 +754,19 @@ static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, flags | BDRV_REQ_ZERO_WRITE); } -static int64_t quorum_getlength(BlockDriverState *bs) +static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs) { BDRVQuorumState *s = bs->opaque; int64_t result; int i; /* check that all file have the same length */ - result = bdrv_getlength(s->children[0]->bs); + result = bdrv_co_getlength(s->children[0]->bs); if (result < 0) { return result; } for (i = 1; i < s->num_children; i++) { - int64_t value = bdrv_getlength(s->children[i]->bs); + int64_t value = bdrv_co_getlength(s->children[i]->bs); if (value < 0) { return value; } @@ -1283,7 +1283,7 @@ static BlockDriver bdrv_quorum = { .bdrv_co_flush = quorum_co_flush, - .bdrv_getlength = quorum_getlength, + .bdrv_co_getlength = quorum_co_getlength, .bdrv_co_preadv = quorum_co_preadv, .bdrv_co_pwritev = quorum_co_pwritev, diff --git a/block/raw-format.c b/block/raw-format.c index b6a0ce58f4..836190a306 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -317,14 +317,14 @@ static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, return bdrv_co_pdiscard(bs->file, offset, bytes); } -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { int64_t len; BDRVRawState *s = bs->opaque; /* Update size. It should not change unless the file was externally * modified. */ - len = bdrv_getlength(bs->file->bs); + len = bdrv_co_getlength(bs->file->bs); if (len < 0) { return len; } @@ -622,7 +622,7 @@ BlockDriver bdrv_raw = { .bdrv_co_copy_range_from = &raw_co_copy_range_from, .bdrv_co_copy_range_to = &raw_co_copy_range_to, .bdrv_co_truncate = &raw_co_truncate, - .bdrv_getlength = &raw_getlength, + .bdrv_co_getlength = &raw_co_getlength, .is_format = true, .has_variable_length = true, .bdrv_measure = &raw_measure, diff --git a/block/rbd.c b/block/rbd.c index 6167c5e424..c127c1550d 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1430,7 +1430,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, return status; } -static int64_t qemu_rbd_getlength(BlockDriverState *bs) +static int64_t coroutine_fn qemu_rbd_co_getlength(BlockDriverState *bs) { BDRVRBDState *s = bs->opaque; int r; @@ -1654,7 +1654,7 @@ static BlockDriver bdrv_rbd = { .bdrv_get_info = qemu_rbd_getinfo, .bdrv_get_specific_info = qemu_rbd_get_specific_info, .create_opts = &qemu_rbd_create_opts, - .bdrv_getlength = qemu_rbd_getlength, + .bdrv_co_getlength = qemu_rbd_co_getlength, .bdrv_co_truncate = qemu_rbd_co_truncate, .protocol_name = "rbd", diff --git a/block/replication.c b/block/replication.c index c62f48a874..a27417d310 100644 --- a/block/replication.c +++ b/block/replication.c @@ -179,9 +179,9 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, return; } -static int64_t replication_getlength(BlockDriverState *bs) +static int64_t coroutine_fn replication_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static int replication_get_io_status(BDRVReplicationState *s) @@ -758,7 +758,7 @@ static BlockDriver bdrv_replication = { .bdrv_close = replication_close, .bdrv_child_perm = replication_child_perm, - .bdrv_getlength = replication_getlength, + .bdrv_co_getlength = replication_co_getlength, .bdrv_co_readv = replication_co_readv, .bdrv_co_writev = replication_co_writev, diff --git a/block/ssh.c b/block/ssh.c index 8bd2a134c1..b3b3352075 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1253,7 +1253,7 @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs) return ret; } -static int64_t ssh_getlength(BlockDriverState *bs) +static int64_t coroutine_fn ssh_co_getlength(BlockDriverState *bs) { BDRVSSHState *s = bs->opaque; int64_t length; @@ -1364,7 +1364,7 @@ static BlockDriver bdrv_ssh = { .bdrv_has_zero_init = ssh_has_zero_init, .bdrv_co_readv = ssh_co_readv, .bdrv_co_writev = ssh_co_writev, - .bdrv_getlength = ssh_getlength, + .bdrv_co_getlength = ssh_co_getlength, .bdrv_co_truncate = ssh_co_truncate, .bdrv_co_flush_to_disk = ssh_co_flush, .bdrv_refresh_filename = ssh_refresh_filename, diff --git a/block/throttle.c b/block/throttle.c index 00cb46d0e5..64fa0f5acc 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -106,9 +106,9 @@ static void throttle_close(BlockDriverState *bs) } -static int64_t throttle_getlength(BlockDriverState *bs) +static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, @@ -247,7 +247,7 @@ static BlockDriver bdrv_throttle = { .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = throttle_getlength, + .bdrv_co_getlength = throttle_co_getlength, .bdrv_co_preadv = throttle_co_preadv, .bdrv_co_pwritev = throttle_co_pwritev, diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e493c28814..d4e360850f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2332,10 +2332,15 @@ static void scsi_disk_reset(DeviceState *dev) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev); uint64_t nb_sectors; + AioContext *ctx; scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET)); + ctx = blk_get_aio_context(s->qdev.conf.blk); + aio_context_acquire(ctx); blk_get_geometry(s->qdev.conf.blk, &nb_sectors); + aio_context_release(ctx); + nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE; if (nb_sectors) { nb_sectors--; diff --git a/include/block/block-io.h b/include/block/block-io.h index f27d935982..dcb6270f77 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -76,8 +76,12 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); -int64_t bdrv_nb_sectors(BlockDriverState *bs); -int64_t bdrv_getlength(BlockDriverState *bs); +int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs); +int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); + +int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs); +int64_t co_wrapper_mixed bdrv_getlength(BlockDriverState *bs); + int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, BlockDriverState *in_bs, Error **errp); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 9ec68f515c..5381681fbc 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -680,7 +680,7 @@ struct BlockDriver { int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); - int64_t (*bdrv_getlength)(BlockDriverState *bs); + int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, Error **errp); diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 37b0fd974b..4430bf4c4a 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -122,7 +122,10 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); -int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); +int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, + int64_t hint); +int co_wrapper_mixed +bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); BdrvChild *bdrv_cow_child(BlockDriverState *bs); BdrvChild *bdrv_filter_child(BlockDriverState *bs); diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 7cc96a56c7..ce013b3312 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -61,9 +61,15 @@ bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); bool blk_is_available(BlockBackend *blk); void blk_lock_medium(BlockBackend *blk, bool locked); void blk_eject(BlockBackend *blk, bool eject_flag); -int64_t blk_getlength(BlockBackend *blk); + +int64_t coroutine_fn blk_co_getlength(BlockBackend *blk); +int64_t co_wrapper_mixed blk_getlength(BlockBackend *blk); + void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); -int64_t blk_nb_sectors(BlockBackend *blk); + +int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk); +int64_t co_wrapper_mixed blk_nb_sectors(BlockBackend *blk); + void *blk_try_blockalign(BlockBackend *blk, size_t size); void *blk_blockalign(BlockBackend *blk, size_t size); bool blk_is_writable(BlockBackend *blk); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index ff5147f619..6dfac6468a 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -832,7 +832,10 @@ static void test_attach_second_node(void) qdict_put_str(options, "driver", "raw"); qdict_put_str(options, "file", "base"); + aio_context_acquire(ctx); filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort); + aio_context_release(ctx); + g_assert(blk_get_aio_context(blk) == ctx); g_assert(bdrv_get_aio_context(bs) == ctx); g_assert(bdrv_get_aio_context(filter) == ctx); From d886257d84dd7c3d3f04c3b1e2e4749b47541ee5 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:05 +0100 Subject: [PATCH 328/814] block-backend: use bdrv_getlength instead of blk_getlength The only difference is that blk_ checks if the block is available, but this check is already performed above in blk_check_byte_request(). This is in preparation for the graph rdlock, which will be taken by both the callers of blk_check_byte_request() and blk_getlength(). Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-8-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block/block-backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/block-backend.c b/block/block-backend.c index d698cc3f33..7d4b08ee45 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1253,7 +1253,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset, } if (!blk->allow_write_beyond_eof) { - len = blk_getlength(blk); + len = bdrv_getlength(blk_bs(blk)); if (len < 0) { return len; } From bd53086e824397a7bf0e875eaa9b339cf8394d75 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:06 +0100 Subject: [PATCH 329/814] block: use bdrv_co_refresh_total_sectors when possible In some places we are sure we are always running in a coroutine, therefore it's useless to call the generated_co_wrapper, instead call directly the _co_ function. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-9-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block/block-backend.c | 6 +++--- block/io.c | 4 ++-- block/preallocate.c | 6 +++--- block/qed.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 7d4b08ee45..b4a8d259cf 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1235,8 +1235,8 @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) blk->disable_request_queuing = disable; } -static int blk_check_byte_request(BlockBackend *blk, int64_t offset, - int64_t bytes) +static coroutine_fn int blk_check_byte_request(BlockBackend *blk, + int64_t offset, int64_t bytes) { int64_t len; @@ -1253,7 +1253,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset, } if (!blk->allow_write_beyond_eof) { - len = bdrv_getlength(blk_bs(blk)); + len = bdrv_co_getlength(blk_bs(blk)); if (len < 0) { return len; } diff --git a/block/io.c b/block/io.c index d78ad87e3c..e77087a7e8 100644 --- a/block/io.c +++ b/block/io.c @@ -3444,7 +3444,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, if (new_bytes && backing) { int64_t backing_len; - backing_len = bdrv_getlength(backing->bs); + backing_len = bdrv_co_getlength(backing->bs); if (backing_len < 0) { ret = backing_len; error_setg_errno(errp, -ret, "Could not get backing file size"); @@ -3474,7 +3474,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, goto out; } - ret = bdrv_refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); + ret = bdrv_co_refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); } else { diff --git a/block/preallocate.c b/block/preallocate.c index c9881942a3..c0dcf8c346 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -287,7 +287,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, } if (s->data_end < 0) { - s->data_end = bdrv_getlength(bs->file->bs); + s->data_end = bdrv_co_getlength(bs->file->bs); if (s->data_end < 0) { return false; } @@ -309,7 +309,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, } if (s->file_end < 0) { - s->file_end = bdrv_getlength(bs->file->bs); + s->file_end = bdrv_co_getlength(bs->file->bs); if (s->file_end < 0) { return false; } @@ -381,7 +381,7 @@ preallocate_co_truncate(BlockDriverState *bs, int64_t offset, if (s->data_end >= 0 && offset > s->data_end) { if (s->file_end < 0) { - s->file_end = bdrv_getlength(bs->file->bs); + s->file_end = bdrv_co_getlength(bs->file->bs); if (s->file_end < 0) { error_setg(errp, "failed to get file length"); return s->file_end; diff --git a/block/qed.c b/block/qed.c index c8f9045b72..16bf0cb080 100644 --- a/block/qed.c +++ b/block/qed.c @@ -424,7 +424,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } /* Round down file size to the last cluster */ - file_size = bdrv_getlength(bs->file->bs); + file_size = bdrv_co_getlength(bs->file->bs); if (file_size < 0) { error_setg(errp, "Failed to get file length"); return file_size; From 82618d7bc341cb93b9ce9c206d7ec84cebe83d00 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:07 +0100 Subject: [PATCH 330/814] block: Convert bdrv_get_allocated_file_size() to co_wrapper bdrv_get_allocated_file_size() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. Therefore turn it into a co_wrapper to move the actual function into a coroutine where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-10-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 12 ++++++------ block/file-posix.c | 14 +++++--------- block/file-win32.c | 10 ++++------ block/gluster.c | 11 ++++++----- block/nfs.c | 4 ++-- block/null.c | 7 ++++--- block/qcow2-refcount.c | 2 +- block/vmdk.c | 9 +++++---- include/block/block-io.h | 4 +++- include/block/block_int-common.h | 4 +++- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/block.c b/block.c index ee6f90990e..15a26e8345 100644 --- a/block.c +++ b/block.c @@ -5720,7 +5720,7 @@ exit: } /** - * Implementation of BlockDriver.bdrv_get_allocated_file_size() that + * Implementation of BlockDriver.bdrv_co_get_allocated_file_size() that * sums the size of all data-bearing children. (This excludes backing * children.) */ @@ -5733,7 +5733,7 @@ static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED)) { - child_size = bdrv_get_allocated_file_size(child->bs); + child_size = bdrv_co_get_allocated_file_size(child->bs); if (child_size < 0) { return child_size; } @@ -5748,7 +5748,7 @@ static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) * Length of a allocated file in bytes. Sparse files are counted by actual * allocated space. Return < 0 if error or unknown. */ -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -5756,8 +5756,8 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) if (!drv) { return -ENOMEDIUM; } - if (drv->bdrv_get_allocated_file_size) { - return drv->bdrv_get_allocated_file_size(bs); + if (drv->bdrv_co_get_allocated_file_size) { + return drv->bdrv_co_get_allocated_file_size(bs); } if (drv->bdrv_file_open) { @@ -5769,7 +5769,7 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) return -ENOTSUP; } else if (drv->is_filter) { /* Filter drivers default to the size of their filtered child */ - return bdrv_get_allocated_file_size(bdrv_filter_bs(bs)); + return bdrv_co_get_allocated_file_size(bdrv_filter_bs(bs)); } else { /* Other drivers default to summing their children's sizes */ return bdrv_sum_allocated_file_size(bs); diff --git a/block/file-posix.c b/block/file-posix.c index b8a42601e9..532ceb82da 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -2464,7 +2464,7 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) } #endif -static int64_t raw_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs) { struct stat st; BDRVRawState *s = bs->opaque; @@ -3324,8 +3324,7 @@ BlockDriver bdrv_file = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .bdrv_get_info = raw_get_info, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = raw_get_specific_stats, .bdrv_check_perm = raw_check_perm, .bdrv_set_perm = raw_set_perm, @@ -3696,8 +3695,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .bdrv_get_info = raw_get_info, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = hdev_get_specific_stats, .bdrv_check_perm = raw_check_perm, .bdrv_set_perm = raw_set_perm, @@ -3820,8 +3818,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .has_variable_length = true, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, @@ -3950,8 +3947,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .has_variable_length = true, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, diff --git a/block/file-win32.c b/block/file-win32.c index 61a3aa27a7..200d244116 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -559,7 +559,7 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) return l.QuadPart; } -static int64_t raw_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs) { typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD * high); @@ -765,8 +765,8 @@ BlockDriver bdrv_file = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size + = raw_co_get_allocated_file_size, .create_opts = &raw_create_opts, }; @@ -935,9 +935,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_getlength = raw_co_getlength, .has_variable_length = true, - - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, }; static void bdrv_file_init(void) diff --git a/block/gluster.c b/block/gluster.c index 0b325e4292..185a83e5e5 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1331,7 +1331,8 @@ static int64_t coroutine_fn qemu_gluster_co_getlength(BlockDriverState *bs) } } -static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +qemu_gluster_co_get_allocated_file_size(BlockDriverState *bs) { BDRVGlusterState *s = bs->opaque; struct stat st; @@ -1560,7 +1561,7 @@ static BlockDriver bdrv_gluster = { .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, .bdrv_co_getlength = qemu_gluster_co_getlength, - .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1589,7 +1590,7 @@ static BlockDriver bdrv_gluster_tcp = { .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, .bdrv_co_getlength = qemu_gluster_co_getlength, - .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1618,7 +1619,7 @@ static BlockDriver bdrv_gluster_unix = { .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, .bdrv_co_getlength = qemu_gluster_co_getlength, - .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1653,7 +1654,7 @@ static BlockDriver bdrv_gluster_rdma = { .bdrv_co_create = qemu_gluster_co_create, .bdrv_co_create_opts = qemu_gluster_co_create_opts, .bdrv_co_getlength = qemu_gluster_co_getlength, - .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, diff --git a/block/nfs.c b/block/nfs.c index 5e288dfc83..351dc6ec8d 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -732,7 +732,7 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data, bdrv_wakeup(task->bs); } -static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs) { NFSClient *client = bs->opaque; NFSRPC task = {0}; @@ -885,7 +885,7 @@ static BlockDriver bdrv_nfs = { .bdrv_has_zero_init = nfs_has_zero_init, /* libnfs does not provide the allocated filesize of a file on win32. */ #if !defined(_WIN32) - .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = nfs_co_get_allocated_file_size, #endif .bdrv_co_truncate = nfs_file_co_truncate, diff --git a/block/null.c b/block/null.c index bc4d0c1d9d..4808704ffd 100644 --- a/block/null.c +++ b/block/null.c @@ -265,7 +265,8 @@ static void null_refresh_filename(BlockDriverState *bs) bs->drv->format_name); } -static int64_t null_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +null_co_get_allocated_file_size(BlockDriverState *bs) { return 0; } @@ -285,7 +286,7 @@ static BlockDriver bdrv_null_co = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_co_parse_filename, .bdrv_co_getlength = null_co_getlength, - .bdrv_get_allocated_file_size = null_allocated_file_size, + .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size, .bdrv_co_preadv = null_co_preadv, .bdrv_co_pwritev = null_co_pwritev, @@ -306,7 +307,7 @@ static BlockDriver bdrv_null_aio = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_aio_parse_filename, .bdrv_co_getlength = null_co_getlength, - .bdrv_get_allocated_file_size = null_allocated_file_size, + .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size, .bdrv_aio_preadv = null_aio_preadv, .bdrv_aio_pwritev = null_aio_pwritev, diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 5ffbefee2e..b092f89da9 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -3720,7 +3720,7 @@ int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs) return file_length; } - real_allocation = bdrv_get_allocated_file_size(bs->file->bs); + real_allocation = bdrv_co_get_allocated_file_size(bs->file->bs); if (real_allocation < 0) { return real_allocation; } diff --git a/block/vmdk.c b/block/vmdk.c index 8894dac2d4..04f50d2e49 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2856,14 +2856,15 @@ static void vmdk_close(BlockDriverState *bs) error_free(s->migration_blocker); } -static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +vmdk_co_get_allocated_file_size(BlockDriverState *bs) { int i; int64_t ret = 0; int64_t r; BDRVVmdkState *s = bs->opaque; - ret = bdrv_get_allocated_file_size(bs->file->bs); + ret = bdrv_co_get_allocated_file_size(bs->file->bs); if (ret < 0) { return ret; } @@ -2871,7 +2872,7 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) if (s->extents[i].file == bs->file) { continue; } - r = bdrv_get_allocated_file_size(s->extents[i].file->bs); + r = bdrv_co_get_allocated_file_size(s->extents[i].file->bs); if (r < 0) { return r; } @@ -3124,7 +3125,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_co_create_opts = vmdk_co_create_opts, .bdrv_co_create = vmdk_co_create, .bdrv_co_block_status = vmdk_co_block_status, - .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = vmdk_co_get_allocated_file_size, .bdrv_has_zero_init = vmdk_has_zero_init, .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, diff --git a/include/block/block-io.h b/include/block/block-io.h index dcb6270f77..89a72ae041 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -82,7 +82,9 @@ int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs); int64_t co_wrapper_mixed bdrv_getlength(BlockDriverState *bs); -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); +int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs); +int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs); + BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, BlockDriverState *in_bs, Error **errp); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 5381681fbc..9e3dda784a 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -681,7 +681,9 @@ struct BlockDriver { bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); - int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); + int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)( + BlockDriverState *bs); + BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, Error **errp); From 3d47eb0a2a42b13734d1beb75c4310b3881f906f Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:08 +0100 Subject: [PATCH 331/814] block: Convert bdrv_get_info() to co_wrapper_mixed bdrv_get_info() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. Therefore turn it into a co_wrapper to move the actual function into a coroutine where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-11-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 8 ++++---- block/blkio.c | 5 +++-- block/crypto.c | 8 ++++---- block/file-posix.c | 7 ++++--- block/io.c | 8 ++++---- block/iscsi.c | 7 ++++--- block/mirror.c | 2 +- block/qcow.c | 5 +++-- block/qcow2.c | 5 +++-- block/qed.c | 5 +++-- block/raw-format.c | 7 ++++--- block/rbd.c | 5 +++-- block/vdi.c | 7 ++++--- block/vhdx.c | 5 +++-- block/vmdk.c | 5 +++-- block/vpc.c | 5 +++-- include/block/block-io.h | 5 ++++- include/block/block_int-common.h | 3 ++- 18 files changed, 59 insertions(+), 43 deletions(-) diff --git a/block.c b/block.c index 15a26e8345..46c7e57959 100644 --- a/block.c +++ b/block.c @@ -6301,7 +6301,7 @@ void bdrv_get_backing_filename(BlockDriverState *bs, pstrcpy(filename, filename_size, bs->backing_file); } -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { int ret; BlockDriver *drv = bs->drv; @@ -6310,15 +6310,15 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) if (!drv) { return -ENOMEDIUM; } - if (!drv->bdrv_get_info) { + if (!drv->bdrv_co_get_info) { BlockDriverState *filtered = bdrv_filter_bs(bs); if (filtered) { - return bdrv_get_info(filtered, bdi); + return bdrv_co_get_info(filtered, bdi); } return -ENOTSUP; } memset(bdi, 0, sizeof(*bdi)); - ret = drv->bdrv_get_info(bs, bdi); + ret = drv->bdrv_co_get_info(bs, bdi); if (ret < 0) { return ret; } diff --git a/block/blkio.c b/block/blkio.c index 284fb292cf..0cdc99a729 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -880,7 +880,8 @@ static int coroutine_fn blkio_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int blkio_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +blkio_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { return 0; } @@ -1000,7 +1001,7 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) .bdrv_close = blkio_close, \ .bdrv_co_getlength = blkio_co_getlength, \ .bdrv_co_truncate = blkio_truncate, \ - .bdrv_get_info = blkio_get_info, \ + .bdrv_co_get_info = blkio_co_get_info, \ .bdrv_attach_aio_context = blkio_attach_aio_context, \ .bdrv_detach_aio_context = blkio_detach_aio_context, \ .bdrv_co_pdiscard = blkio_co_pdiscard, \ diff --git a/block/crypto.c b/block/crypto.c index 6d6c006887..b70cec97c7 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -737,13 +737,13 @@ fail: return ret; } -static int block_crypto_get_info_luks(BlockDriverState *bs, - BlockDriverInfo *bdi) +static int coroutine_fn +block_crypto_co_get_info_luks(BlockDriverState *bs, BlockDriverInfo *bdi) { BlockDriverInfo subbdi; int ret; - ret = bdrv_get_info(bs->file->bs, &subbdi); + ret = bdrv_co_get_info(bs->file->bs, &subbdi); if (ret != 0) { return ret; } @@ -955,7 +955,7 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_co_pwritev = block_crypto_co_pwritev, .bdrv_co_getlength = block_crypto_co_getlength, .bdrv_measure = block_crypto_measure, - .bdrv_get_info = block_crypto_get_info_luks, + .bdrv_co_get_info = block_crypto_co_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, .bdrv_amend_options = block_crypto_amend_options_luks, .bdrv_co_amend = block_crypto_co_amend_luks, diff --git a/block/file-posix.c b/block/file-posix.c index 532ceb82da..c76ed7d9a7 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3086,7 +3086,8 @@ static int coroutine_fn raw_co_pwrite_zeroes( return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false); } -static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { return 0; } @@ -3323,7 +3324,7 @@ BlockDriver bdrv_file = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, - .bdrv_get_info = raw_get_info, + .bdrv_co_get_info = raw_co_get_info, .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = raw_get_specific_stats, .bdrv_check_perm = raw_check_perm, @@ -3694,7 +3695,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, - .bdrv_get_info = raw_get_info, + .bdrv_co_get_info = raw_co_get_info, .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = hdev_get_specific_stats, .bdrv_check_perm = raw_check_perm, diff --git a/block/io.c b/block/io.c index e77087a7e8..15d57d0f14 100644 --- a/block/io.c +++ b/block/io.c @@ -722,14 +722,14 @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) /** * Round a region to cluster boundaries */ -void bdrv_round_to_clusters(BlockDriverState *bs, +void coroutine_fn bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *cluster_offset, int64_t *cluster_bytes) { BlockDriverInfo bdi; IO_CODE(); - if (bdrv_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { + if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { *cluster_offset = offset; *cluster_bytes = bytes; } else { @@ -739,12 +739,12 @@ void bdrv_round_to_clusters(BlockDriverState *bs, } } -static int bdrv_get_cluster_size(BlockDriverState *bs) +static coroutine_fn int bdrv_get_cluster_size(BlockDriverState *bs) { BlockDriverInfo bdi; int ret; - ret = bdrv_get_info(bs, &bdi); + ret = bdrv_co_get_info(bs, &bdi); if (ret < 0 || bdi.cluster_size == 0) { return bs->bl.request_alignment; } else { diff --git a/block/iscsi.c b/block/iscsi.c index 359b532a33..b3e10f40b6 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2171,7 +2171,8 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +iscsi_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { IscsiLun *iscsilun = bs->opaque; bdi->cluster_size = iscsilun->cluster_size; @@ -2435,7 +2436,7 @@ static BlockDriver bdrv_iscsi = { .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, .bdrv_co_getlength = iscsi_co_getlength, - .bdrv_get_info = iscsi_get_info, + .bdrv_co_get_info = iscsi_co_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, @@ -2474,7 +2475,7 @@ static BlockDriver bdrv_iser = { .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, .bdrv_co_getlength = iscsi_co_getlength, - .bdrv_get_info = iscsi_get_info, + .bdrv_co_get_info = iscsi_co_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, diff --git a/block/mirror.c b/block/mirror.c index 7ed4dbde04..ab326b67c9 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -957,7 +957,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) */ bdrv_get_backing_filename(target_bs, backing_filename, sizeof(backing_filename)); - if (!bdrv_get_info(target_bs, &bdi) && bdi.cluster_size) { + if (!bdrv_co_get_info(target_bs, &bdi) && bdi.cluster_size) { s->target_cluster_size = bdi.cluster_size; } else { s->target_cluster_size = BDRV_SECTOR_SIZE; diff --git a/block/qcow.c b/block/qcow.c index 5d99f00411..5f0801f545 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -1129,7 +1129,8 @@ fail: return ret; } -static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qcow_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcowState *s = bs->opaque; bdi->cluster_size = s->cluster_size; @@ -1198,7 +1199,7 @@ static BlockDriver bdrv_qcow = { .bdrv_make_empty = qcow_make_empty, .bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed, - .bdrv_get_info = qcow_get_info, + .bdrv_co_get_info = qcow_co_get_info, .create_opts = &qcow_create_opts, .strong_runtime_opts = qcow_strong_runtime_opts, diff --git a/block/qcow2.c b/block/qcow2.c index 2e9c57e269..5effd4b732 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5143,7 +5143,8 @@ err: return NULL; } -static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcow2State *s = bs->opaque; bdi->cluster_size = s->cluster_size; @@ -6077,7 +6078,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_list = qcow2_snapshot_list, .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, .bdrv_measure = qcow2_measure, - .bdrv_get_info = qcow2_get_info, + .bdrv_co_get_info = qcow2_co_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, .bdrv_save_vmstate = qcow2_save_vmstate, diff --git a/block/qed.c b/block/qed.c index 16bf0cb080..4473465bba 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1486,7 +1486,8 @@ static int64_t coroutine_fn bdrv_qed_co_getlength(BlockDriverState *bs) return s->header.image_size; } -static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +bdrv_qed_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQEDState *s = bs->opaque; @@ -1654,7 +1655,7 @@ static BlockDriver bdrv_qed = { .bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes, .bdrv_co_truncate = bdrv_qed_co_truncate, .bdrv_co_getlength = bdrv_qed_co_getlength, - .bdrv_get_info = bdrv_qed_get_info, + .bdrv_co_get_info = bdrv_qed_co_get_info, .bdrv_refresh_limits = bdrv_qed_refresh_limits, .bdrv_change_backing_file = bdrv_qed_change_backing_file, .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache, diff --git a/block/raw-format.c b/block/raw-format.c index 836190a306..33d94e290b 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -368,9 +368,10 @@ static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs, return info; } -static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - return bdrv_get_info(bs->file->bs, bdi); + return bdrv_co_get_info(bs->file->bs, bdi); } static void raw_refresh_limits(BlockDriverState *bs, Error **errp) @@ -626,7 +627,7 @@ BlockDriver bdrv_raw = { .is_format = true, .has_variable_length = true, .bdrv_measure = &raw_measure, - .bdrv_get_info = &raw_get_info, + .bdrv_co_get_info = &raw_co_get_info, .bdrv_refresh_limits = &raw_refresh_limits, .bdrv_probe_blocksizes = &raw_probe_blocksizes, .bdrv_probe_geometry = &raw_probe_geometry, diff --git a/block/rbd.c b/block/rbd.c index c127c1550d..5e102fea0d 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1240,7 +1240,8 @@ coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, } #endif -static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qemu_rbd_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVRBDState *s = bs->opaque; bdi->cluster_size = s->object_size; @@ -1651,7 +1652,7 @@ static BlockDriver bdrv_rbd = { .bdrv_co_create = qemu_rbd_co_create, .bdrv_co_create_opts = qemu_rbd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_get_info = qemu_rbd_getinfo, + .bdrv_co_get_info = qemu_rbd_co_get_info, .bdrv_get_specific_info = qemu_rbd_get_specific_info, .create_opts = &qemu_rbd_create_opts, .bdrv_co_getlength = qemu_rbd_co_getlength, diff --git a/block/vdi.c b/block/vdi.c index 479bcfe820..9c8736b26f 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -327,9 +327,10 @@ static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, return 0; } -static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vdi_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - /* TODO: vdi_get_info would be needed for machine snapshots. + /* TODO: vdi_co_get_info would be needed for machine snapshots. vm_state_offset is still missing. */ BDRVVdiState *s = (BDRVVdiState *)bs->opaque; logout("\n"); @@ -1049,7 +1050,7 @@ static BlockDriver bdrv_vdi = { .bdrv_co_pwritev = vdi_co_pwritev, #endif - .bdrv_get_info = vdi_get_info, + .bdrv_co_get_info = vdi_co_get_info, .is_format = true, .create_opts = &vdi_create_opts, diff --git a/block/vhdx.c b/block/vhdx.c index 4c929800fe..ef1f65d917 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1161,7 +1161,8 @@ static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num, } -static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vhdx_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVVHDXState *s = bs->opaque; @@ -2245,7 +2246,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_co_writev = vhdx_co_writev, .bdrv_co_create = vhdx_co_create, .bdrv_co_create_opts = vhdx_co_create_opts, - .bdrv_get_info = vhdx_get_info, + .bdrv_co_get_info = vhdx_co_get_info, .bdrv_co_check = vhdx_co_check, .bdrv_has_zero_init = vhdx_has_zero_init, diff --git a/block/vmdk.c b/block/vmdk.c index 04f50d2e49..1bba61ad7d 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -3012,7 +3012,8 @@ static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) (a->flat || a->cluster_sectors == b->cluster_sectors); } -static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vmdk_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { int i; BDRVVmdkState *s = bs->opaque; @@ -3129,7 +3130,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_has_zero_init = vmdk_has_zero_init, .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, - .bdrv_get_info = vmdk_get_info, + .bdrv_co_get_info = vmdk_co_get_info, .bdrv_gather_child_options = vmdk_gather_child_options, .is_format = true, diff --git a/block/vpc.c b/block/vpc.c index 6ee95dcb96..cfdea7db80 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -598,7 +598,8 @@ fail: return ret; } -static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vpc_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVVPCState *s = (BDRVVPCState *)bs->opaque; @@ -1240,7 +1241,7 @@ static BlockDriver bdrv_vpc = { .bdrv_co_pwritev = vpc_co_pwritev, .bdrv_co_block_status = vpc_co_block_status, - .bdrv_get_info = vpc_get_info, + .bdrv_co_get_info = vpc_co_get_info, .is_format = true, .create_opts = &vpc_create_opts, diff --git a/include/block/block-io.h b/include/block/block-io.h index 89a72ae041..ed5a0fd01b 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -154,7 +154,10 @@ bool bdrv_supports_compressed_writes(BlockDriverState *bs); const char *bdrv_get_node_name(const BlockDriverState *bs); const char *bdrv_get_device_name(const BlockDriverState *bs); const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + +int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); +int co_wrapper_mixed bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, Error **errp); BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 9e3dda784a..7c9406a6df 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -693,7 +693,8 @@ struct BlockDriver { int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); - int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + int coroutine_fn (*bdrv_co_get_info)(BlockDriverState *bs, + BlockDriverInfo *bdi); ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, Error **errp); From 2531b390fbf67ceccf63f7d236ab2a998f135624 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:09 +0100 Subject: [PATCH 332/814] block: Convert bdrv_eject() to co_wrapper bdrv_eject() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. The only caller of this function is blk_eject(). Therefore make blk_eject() a co_wrapper, so that it always creates a new coroutine, and then make bdrv_eject() coroutine_fn where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-12-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 6 +++--- block/block-backend.c | 4 ++-- block/copy-on-read.c | 6 +++--- block/file-posix.c | 8 ++++---- block/filter-compress.c | 7 ++++--- block/raw-format.c | 6 +++--- include/block/block-io.h | 3 ++- include/block/block_int-common.h | 2 +- include/sysemu/block-backend-io.h | 4 +++- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/block.c b/block.c index 46c7e57959..61ece8207d 100644 --- a/block.c +++ b/block.c @@ -6821,13 +6821,13 @@ bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs) /** * If eject_flag is TRUE, eject the media. Otherwise, close the tray */ -void bdrv_eject(BlockDriverState *bs, bool eject_flag) +void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag) { BlockDriver *drv = bs->drv; IO_CODE(); - if (drv && drv->bdrv_eject) { - drv->bdrv_eject(bs, eject_flag); + if (drv && drv->bdrv_co_eject) { + drv->bdrv_co_eject(bs, eject_flag); } } diff --git a/block/block-backend.c b/block/block-backend.c index b4a8d259cf..7eaafc85b1 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2009,14 +2009,14 @@ void blk_lock_medium(BlockBackend *blk, bool locked) } } -void blk_eject(BlockBackend *blk, bool eject_flag) +void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag) { BlockDriverState *bs = blk_bs(blk); char *id; IO_CODE(); if (bs) { - bdrv_eject(bs, eject_flag); + bdrv_co_eject(bs, eject_flag); } /* Whether or not we ejected on the backend, diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 8cad979e29..4204931277 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -217,9 +217,9 @@ static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs, } -static void cor_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } @@ -258,7 +258,7 @@ static BlockDriver bdrv_copy_on_read = { .bdrv_co_pdiscard = cor_co_pdiscard, .bdrv_co_pwritev_compressed = cor_co_pwritev_compressed, - .bdrv_eject = cor_eject, + .bdrv_co_eject = cor_co_eject, .bdrv_lock_medium = cor_lock_medium, .has_variable_length = true, diff --git a/block/file-posix.c b/block/file-posix.c index c76ed7d9a7..a223dba7a5 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3765,7 +3765,7 @@ static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) return ret == CDS_DISC_OK; } -static void cdrom_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) { BDRVRawState *s = bs->opaque; @@ -3823,7 +3823,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, - .bdrv_eject = cdrom_eject, + .bdrv_co_eject = cdrom_co_eject, .bdrv_lock_medium = cdrom_lock_medium, /* generic scsi device */ @@ -3886,7 +3886,7 @@ static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) return raw_co_getlength(bs) > 0; } -static void cdrom_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) { BDRVRawState *s = bs->opaque; @@ -3952,7 +3952,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, - .bdrv_eject = cdrom_eject, + .bdrv_co_eject = cdrom_co_eject, .bdrv_lock_medium = cdrom_lock_medium, }; #endif /* __FreeBSD__ */ diff --git a/block/filter-compress.c b/block/filter-compress.c index bcf76ac910..1e869bd304 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -117,9 +117,10 @@ static void compress_refresh_limits(BlockDriverState *bs, Error **errp) } -static void compress_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn +compress_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } @@ -143,7 +144,7 @@ static BlockDriver bdrv_compress = { .bdrv_co_pdiscard = compress_co_pdiscard, .bdrv_refresh_limits = compress_refresh_limits, - .bdrv_eject = compress_eject, + .bdrv_co_eject = compress_co_eject, .bdrv_lock_medium = compress_lock_medium, .has_variable_length = true, diff --git a/block/raw-format.c b/block/raw-format.c index 33d94e290b..21aa7fdaaf 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -405,9 +405,9 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); } -static void raw_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } static void raw_lock_medium(BlockDriverState *bs, bool locked) @@ -631,7 +631,7 @@ BlockDriver bdrv_raw = { .bdrv_refresh_limits = &raw_refresh_limits, .bdrv_probe_blocksizes = &raw_probe_blocksizes, .bdrv_probe_geometry = &raw_probe_geometry, - .bdrv_eject = &raw_eject, + .bdrv_co_eject = &raw_co_eject, .bdrv_lock_medium = &raw_lock_medium, .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, diff --git a/include/block/block-io.h b/include/block/block-io.h index ed5a0fd01b..ecf62cdc4e 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -147,7 +147,8 @@ bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs); bool co_wrapper bdrv_is_inserted(BlockDriverState *bs); void bdrv_lock_medium(BlockDriverState *bs, bool locked); -void bdrv_eject(BlockDriverState *bs, bool eject_flag); +void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag); + const char *bdrv_get_format_name(BlockDriverState *bs); bool bdrv_supports_compressed_writes(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 7c9406a6df..41429660de 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -708,7 +708,7 @@ struct BlockDriver { /* removable device specific */ bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs); - void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); + void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag); void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); /* to control generic scsi devices */ diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index ce013b3312..3db103087c 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -60,7 +60,9 @@ bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); bool blk_is_available(BlockBackend *blk); void blk_lock_medium(BlockBackend *blk, bool locked); -void blk_eject(BlockBackend *blk, bool eject_flag); + +void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag); +void co_wrapper blk_eject(BlockBackend *blk, bool eject_flag); int64_t coroutine_fn blk_co_getlength(BlockBackend *blk); int64_t co_wrapper_mixed blk_getlength(BlockBackend *blk); From 2c75261cc2b5d1cdd6f012d7a3ccbc089f966dcb Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:10 +0100 Subject: [PATCH 333/814] block: Convert bdrv_lock_medium() to co_wrapper bdrv_lock_medium() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. The only caller of this function is blk_lock_medium(). Therefore make blk_lock_medium() a co_wrapper, so that it always creates a new coroutine, and then make bdrv_lock_medium() a coroutine_fn where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-13-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 6 +++--- block/block-backend.c | 4 ++-- block/copy-on-read.c | 6 +++--- block/file-posix.c | 8 ++++---- block/filter-compress.c | 7 ++++--- block/raw-format.c | 6 +++--- include/block/block-io.h | 2 +- include/block/block_int-common.h | 2 +- include/sysemu/block-backend-io.h | 4 +++- 9 files changed, 24 insertions(+), 21 deletions(-) diff --git a/block.c b/block.c index 61ece8207d..bd016ef72f 100644 --- a/block.c +++ b/block.c @@ -6835,14 +6835,14 @@ void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag) * Lock or unlock the media (if it is locked, the user won't be able * to eject it manually). */ -void bdrv_lock_medium(BlockDriverState *bs, bool locked) +void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked) { BlockDriver *drv = bs->drv; IO_CODE(); trace_bdrv_lock_medium(bs, locked); - if (drv && drv->bdrv_lock_medium) { - drv->bdrv_lock_medium(bs, locked); + if (drv && drv->bdrv_co_lock_medium) { + drv->bdrv_co_lock_medium(bs, locked); } } diff --git a/block/block-backend.c b/block/block-backend.c index 7eaafc85b1..ef512f7c48 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1999,13 +1999,13 @@ bool blk_is_available(BlockBackend *blk) return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk); } -void blk_lock_medium(BlockBackend *blk, bool locked) +void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_lock_medium(bs, locked); + bdrv_co_lock_medium(bs, locked); } } diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 4204931277..3280eb2feb 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -223,9 +223,9 @@ static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag) } -static void cor_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cor_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } @@ -259,7 +259,7 @@ static BlockDriver bdrv_copy_on_read = { .bdrv_co_pwritev_compressed = cor_co_pwritev_compressed, .bdrv_co_eject = cor_co_eject, - .bdrv_lock_medium = cor_lock_medium, + .bdrv_co_lock_medium = cor_co_lock_medium, .has_variable_length = true, .is_filter = true, diff --git a/block/file-posix.c b/block/file-posix.c index a223dba7a5..fa6aeea99d 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3778,7 +3778,7 @@ static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) } } -static void cdrom_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cdrom_co_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -3824,7 +3824,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, .bdrv_co_eject = cdrom_co_eject, - .bdrv_lock_medium = cdrom_lock_medium, + .bdrv_co_lock_medium = cdrom_co_lock_medium, /* generic scsi device */ .bdrv_co_ioctl = hdev_co_ioctl, @@ -3906,7 +3906,7 @@ static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) cdrom_reopen(bs); } -static void cdrom_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cdrom_co_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -3953,7 +3953,7 @@ static BlockDriver bdrv_host_cdrom = { /* removable device support */ .bdrv_co_is_inserted = cdrom_co_is_inserted, .bdrv_co_eject = cdrom_co_eject, - .bdrv_lock_medium = cdrom_lock_medium, + .bdrv_co_lock_medium = cdrom_co_lock_medium, }; #endif /* __FreeBSD__ */ diff --git a/block/filter-compress.c b/block/filter-compress.c index 1e869bd304..2e2a65966c 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -124,9 +124,10 @@ compress_co_eject(BlockDriverState *bs, bool eject_flag) } -static void compress_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn +compress_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } @@ -145,7 +146,7 @@ static BlockDriver bdrv_compress = { .bdrv_refresh_limits = compress_refresh_limits, .bdrv_co_eject = compress_co_eject, - .bdrv_lock_medium = compress_lock_medium, + .bdrv_co_lock_medium = compress_co_lock_medium, .has_variable_length = true, .is_filter = true, diff --git a/block/raw-format.c b/block/raw-format.c index 21aa7fdaaf..0dc469b629 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -410,9 +410,9 @@ static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag) bdrv_co_eject(bs->file->bs, eject_flag); } -static void raw_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, @@ -632,7 +632,7 @@ BlockDriver bdrv_raw = { .bdrv_probe_blocksizes = &raw_probe_blocksizes, .bdrv_probe_geometry = &raw_probe_geometry, .bdrv_co_eject = &raw_co_eject, - .bdrv_lock_medium = &raw_lock_medium, + .bdrv_co_lock_medium = &raw_co_lock_medium, .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, .bdrv_has_zero_init = &raw_has_zero_init, diff --git a/include/block/block-io.h b/include/block/block-io.h index ecf62cdc4e..a1823eee94 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -146,7 +146,7 @@ int bdrv_get_flags(BlockDriverState *bs); bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs); bool co_wrapper bdrv_is_inserted(BlockDriverState *bs); -void bdrv_lock_medium(BlockDriverState *bs, bool locked); +void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked); void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag); const char *bdrv_get_format_name(BlockDriverState *bs); diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 41429660de..64b05fd030 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -709,7 +709,7 @@ struct BlockDriver { /* removable device specific */ bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs); void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag); - void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); + void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); /* to control generic scsi devices */ BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 3db103087c..b1196ab93c 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -59,7 +59,9 @@ bool coroutine_fn blk_co_is_inserted(BlockBackend *blk); bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); bool blk_is_available(BlockBackend *blk); -void blk_lock_medium(BlockBackend *blk, bool locked); + +void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked); +void co_wrapper blk_lock_medium(BlockBackend *blk, bool locked); void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag); void co_wrapper blk_eject(BlockBackend *blk, bool eject_flag); From c834dc05863e1254b379d73baeb04d24ced01e8c Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:11 +0100 Subject: [PATCH 334/814] block: Convert bdrv_debug_event() to co_wrapper_mixed bdrv_debug_event() is categorized as an I/O function, and it currently doesn't run in a coroutine. We should let it take a graph rdlock since it traverses the block nodes graph, which however is only possible in a coroutine. Therefore turn it into a co_wrapper_mixed to move the actual function into a coroutine where the lock can be taken. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-14-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block.c | 6 +++--- block/blkdebug.c | 5 +++-- block/io.c | 22 +++++++++++----------- include/block/block-io.h | 5 ++++- include/block/block_int-common.h | 3 ++- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/block.c b/block.c index bd016ef72f..aa9062f2c1 100644 --- a/block.c +++ b/block.c @@ -6351,14 +6351,14 @@ BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs) return drv->bdrv_get_specific_stats(bs); } -void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) +void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event) { IO_CODE(); - if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { + if (!bs || !bs->drv || !bs->drv->bdrv_co_debug_event) { return; } - bs->drv->bdrv_debug_event(bs, event); + bs->drv->bdrv_co_debug_event(bs, event); } static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) diff --git a/block/blkdebug.c b/block/blkdebug.c index e6dc0ba142..28772be73f 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -836,7 +836,8 @@ static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, } } -static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) +static void coroutine_fn +blkdebug_co_debug_event(BlockDriverState *bs, BlkdebugEvent event) { BDRVBlkdebugState *s = bs->opaque; struct BlkdebugRule *rule, *next; @@ -1086,7 +1087,7 @@ static BlockDriver bdrv_blkdebug = { .bdrv_co_pdiscard = blkdebug_co_pdiscard, .bdrv_co_block_status = blkdebug_co_block_status, - .bdrv_debug_event = blkdebug_debug_event, + .bdrv_co_debug_event = blkdebug_co_debug_event, .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, .bdrv_debug_remove_breakpoint = blkdebug_debug_remove_breakpoint, diff --git a/block/io.c b/block/io.c index 15d57d0f14..5039995f7c 100644 --- a/block/io.c +++ b/block/io.c @@ -1251,7 +1251,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, goto err; } - bdrv_debug_event(bs, BLKDBG_COR_WRITE); + bdrv_co_debug_event(bs, BLKDBG_COR_WRITE); if (drv->bdrv_co_pwrite_zeroes && buffer_is_zero(bounce_buffer, pnum)) { /* FIXME: Should we (perhaps conditionally) be setting @@ -1496,10 +1496,10 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, qemu_iovec_init_buf(&local_qiov, pad->buf, bytes); if (pad->head) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); } if (pad->merge_reads && pad->tail) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); } ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes, align, &local_qiov, 0, 0); @@ -1507,10 +1507,10 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, return ret; } if (pad->head) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); } if (pad->merge_reads && pad->tail) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); } if (pad->merge_reads) { @@ -1521,7 +1521,7 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, if (pad->tail) { qemu_iovec_init_buf(&local_qiov, pad->tail_buf, align); - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ret = bdrv_aligned_preadv( child, req, req->overlap_offset + req->overlap_bytes - align, @@ -1529,7 +1529,7 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, if (ret < 0) { return ret; } - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); } zero_mem: @@ -1931,16 +1931,16 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, if (ret < 0) { /* Do nothing, write notifier decided to fail this request */ } else if (flags & BDRV_REQ_ZERO_WRITE) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_ZERO); ret = bdrv_co_do_pwrite_zeroes(bs, offset, bytes, flags); } else if (flags & BDRV_REQ_WRITE_COMPRESSED) { ret = bdrv_driver_pwritev_compressed(bs, offset, bytes, qiov, qiov_offset); } else if (bytes <= max_transfer) { - bdrv_debug_event(bs, BLKDBG_PWRITEV); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV); ret = bdrv_driver_pwritev(bs, offset, bytes, qiov, qiov_offset, flags); } else { - bdrv_debug_event(bs, BLKDBG_PWRITEV); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV); while (bytes_remaining) { int num = MIN(bytes_remaining, max_transfer); int local_flags = flags; @@ -1963,7 +1963,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, bytes_remaining -= num; } } - bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_DONE); if (ret >= 0) { ret = 0; diff --git a/include/block/block-io.h b/include/block/block-io.h index a1823eee94..614cbd7eda 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -191,7 +191,10 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); -void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event); +void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, + BlkdebugEvent event); +void co_wrapper_mixed bdrv_debug_event(BlockDriverState *bs, + BlkdebugEvent event); #define BLKDBG_EVENT(child, evt) \ do { \ diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 64b05fd030..0a6b7ec48b 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -725,7 +725,8 @@ struct BlockDriver { int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_check)( BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix); - void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); + void coroutine_fn (*bdrv_co_debug_event)(BlockDriverState *bs, + BlkdebugEvent event); /* io queue for linux-aio */ void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs); From ca5e2ad98d4475a5f938ad5b65cc10e819190bba Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Fri, 13 Jan 2023 21:42:12 +0100 Subject: [PATCH 335/814] block: Rename bdrv_load/save_vmstate() to bdrv_co_load/save_vmstate() Since these functions always run in coroutine context, adjust their name to include "_co_", just like all other BlockDriver callbacks. No functional change intended. Signed-off-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230113204212.359076-15-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf --- block/io.c | 8 ++++---- block/qcow2.c | 12 ++++++------ include/block/block_int-common.h | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/block/io.c b/block/io.c index 5039995f7c..2dc0c13e41 100644 --- a/block/io.c +++ b/block/io.c @@ -2720,8 +2720,8 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) bdrv_inc_in_flight(bs); - if (drv->bdrv_load_vmstate) { - ret = drv->bdrv_load_vmstate(bs, qiov, pos); + if (drv->bdrv_co_load_vmstate) { + ret = drv->bdrv_co_load_vmstate(bs, qiov, pos); } else if (child_bs) { ret = bdrv_co_readv_vmstate(child_bs, qiov, pos); } else { @@ -2753,8 +2753,8 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) bdrv_inc_in_flight(bs); - if (drv->bdrv_save_vmstate) { - ret = drv->bdrv_save_vmstate(bs, qiov, pos); + if (drv->bdrv_co_save_vmstate) { + ret = drv->bdrv_co_save_vmstate(bs, qiov, pos); } else if (child_bs) { ret = bdrv_co_writev_vmstate(child_bs, qiov, pos); } else { diff --git a/block/qcow2.c b/block/qcow2.c index 5effd4b732..21aa4c6b7a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5287,8 +5287,8 @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs, return pos; } -static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos) +static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -5299,8 +5299,8 @@ static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs, return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); } -static coroutine_fn int qcow2_load_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos) +static coroutine_fn int qcow2_co_load_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -6081,8 +6081,8 @@ BlockDriver bdrv_qcow2 = { .bdrv_co_get_info = qcow2_co_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, - .bdrv_save_vmstate = qcow2_save_vmstate, - .bdrv_load_vmstate = qcow2_load_vmstate, + .bdrv_co_save_vmstate = qcow2_co_save_vmstate, + .bdrv_co_load_vmstate = qcow2_co_load_vmstate, .is_format = true, .supports_backing = true, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 0a6b7ec48b..ba2e0fce25 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -700,10 +700,10 @@ struct BlockDriver { Error **errp); BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); - int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_save_vmstate)( + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_save_vmstate)( BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); - int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_load_vmstate)( + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_load_vmstate)( BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); /* removable device specific */ From fcb9e05144db51966e1476790129dbff92a0bea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 25 Nov 2022 18:53:28 +0100 Subject: [PATCH 336/814] block/nbd: Add missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inlined nbd_readXX() functions call beXX_to_cpu(), themselves declared in . This fixes when refactoring: In file included from ../../block/nbd.c:44: include/block/nbd.h: In function 'nbd_read16': include/block/nbd.h:383:12: error: implicit declaration of function 'be16_to_cpu' [-Werror=implicit-function-declaration] 383 | *val = be##bits##_to_cpu(*val); \ | ^~ include/block/nbd.h:387:1: note: in expansion of macro 'DEF_NBD_READ_N' 387 | DEF_NBD_READ_N(16) /* Defines nbd_read16(). */ | ^~~~~~~~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20221125175328.48539-1-philmd@linaro.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/block/nbd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/block/nbd.h b/include/block/nbd.h index 4ede3b2bd0..a4c98169c3 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -24,6 +24,7 @@ #include "io/channel-socket.h" #include "crypto/tlscreds.h" #include "qapi/error.h" +#include "qemu/bswap.h" extern const BlockExportDriver blk_exp_nbd; From 3716470b24f0f63090d59bcf28ad8fe6fb7835bd Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:53 +0200 Subject: [PATCH 337/814] block: Improve empty format-specific info dump When a block driver supports obtaining format-specific information, but that object only contains optional fields, it is possible that none of them are present, so that dump_qobject() (called by bdrv_image_info_specific_dump()) will not print anything. The callers of bdrv_image_info_specific_dump() put a header above this information ("Format specific information:\n"), which will look strange when there is nothing below. Modify bdrv_image_info_specific_dump() to print this header instead of its callers, and only if there is indeed something to be printed. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-2-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qapi.c | 41 +++++++++++++++++++++++++++++++++++++---- include/block/qapi.h | 3 ++- qemu-io-cmds.c | 4 ++-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index 9b4da12966..0551875902 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -760,7 +760,35 @@ static void dump_qdict(int indentation, QDict *dict) } } -void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) +/* + * Return whether dumping the given QObject with dump_qobject() would + * yield an empty dump, i.e. not print anything. + */ +static bool qobject_is_empty_dump(const QObject *obj) +{ + switch (qobject_type(obj)) { + case QTYPE_QNUM: + case QTYPE_QSTRING: + case QTYPE_QBOOL: + return false; + + case QTYPE_QDICT: + return qdict_size(qobject_to(QDict, obj)) == 0; + + case QTYPE_QLIST: + return qlist_empty(qobject_to(QList, obj)); + + default: + abort(); + } +} + +/** + * Dumps the given ImageInfoSpecific object in a human-readable form, + * prepending an optional prefix if the dump is not empty. + */ +void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix) { QObject *obj, *data; Visitor *v = qobject_output_visitor_new(&obj); @@ -768,7 +796,12 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort); visit_complete(v, &obj); data = qdict_get(qobject_to(QDict, obj), "data"); - dump_qobject(1, data); + if (!qobject_is_empty_dump(data)) { + if (prefix) { + qemu_printf("%s", prefix); + } + dump_qobject(1, data); + } qobject_unref(obj); visit_free(v); } @@ -849,7 +882,7 @@ void bdrv_image_info_dump(ImageInfo *info) } if (info->format_specific) { - qemu_printf("Format specific information:\n"); - bdrv_image_info_specific_dump(info->format_specific); + bdrv_image_info_specific_dump(info->format_specific, + "Format specific information:\n"); } } diff --git a/include/block/qapi.h b/include/block/qapi.h index 865fb974d4..902fec81d5 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -40,6 +40,7 @@ void bdrv_query_image_info(BlockDriverState *bs, Error **errp); void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); -void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec); +void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix); void bdrv_image_info_dump(ImageInfo *info); #endif diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 7a412d6512..d7e562dda6 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -1788,8 +1788,8 @@ static int info_f(BlockBackend *blk, int argc, char **argv) return -EIO; } if (spec_info) { - printf("Format specific information:\n"); - bdrv_image_info_specific_dump(spec_info); + bdrv_image_info_specific_dump(spec_info, + "Format specific information:\n"); qapi_free_ImageInfoSpecific(spec_info); } From 7f36a50ab4e7d39369cac67be4ba9d6ee4081dc0 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:54 +0200 Subject: [PATCH 338/814] block/file: Add file-specific image info Add some (optional) information that the file driver can provide for image files, namely the extent size hint. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-3-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/file-posix.c | 30 ++++++++++++++++++++++++++++++ qapi/block-core.json | 26 ++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index fa6aeea99d..d3073a7caa 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3092,6 +3092,34 @@ raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } +static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs, + Error **errp) +{ + ImageInfoSpecificFile *file_info = g_new0(ImageInfoSpecificFile, 1); + ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1); + + *spec_info = (ImageInfoSpecific){ + .type = IMAGE_INFO_SPECIFIC_KIND_FILE, + .u.file.data = file_info, + }; + +#ifdef FS_IOC_FSGETXATTR + { + BDRVRawState *s = bs->opaque; + struct fsxattr attr; + int ret; + + ret = ioctl(s->fd, FS_IOC_FSGETXATTR, &attr); + if (!ret && attr.fsx_extsize != 0) { + file_info->has_extent_size_hint = true; + file_info->extent_size_hint = attr.fsx_extsize; + } + } +#endif + + return spec_info; +} + static BlockStatsSpecificFile get_blockstats_specific_file(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -3325,6 +3353,7 @@ BlockDriver bdrv_file = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .bdrv_co_get_info = raw_co_get_info, + .bdrv_get_specific_info = raw_get_specific_info, .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = raw_get_specific_stats, .bdrv_check_perm = raw_check_perm, @@ -3696,6 +3725,7 @@ static BlockDriver bdrv_host_device = { .bdrv_co_truncate = raw_co_truncate, .bdrv_co_getlength = raw_co_getlength, .bdrv_co_get_info = raw_co_get_info, + .bdrv_get_specific_info = raw_get_specific_info, .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = hdev_get_specific_stats, .bdrv_check_perm = raw_check_perm, diff --git a/qapi/block-core.json b/qapi/block-core.json index 95ac4fa634..f5d822cbd6 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -139,16 +139,29 @@ '*encryption-format': 'RbdImageEncryptionFormat' } } +## +# @ImageInfoSpecificFile: +# +# @extent-size-hint: Extent size hint (if available) +# +# Since: 8.0 +## +{ 'struct': 'ImageInfoSpecificFile', + 'data': { + '*extent-size-hint': 'size' + } } + ## # @ImageInfoSpecificKind: # # @luks: Since 2.7 # @rbd: Since 6.1 +# @file: Since 8.0 # # Since: 1.7 ## { 'enum': 'ImageInfoSpecificKind', - 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd' ] } + 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd', 'file' ] } ## # @ImageInfoSpecificQCow2Wrapper: @@ -185,6 +198,14 @@ { 'struct': 'ImageInfoSpecificRbdWrapper', 'data': { 'data': 'ImageInfoSpecificRbd' } } +## +# @ImageInfoSpecificFileWrapper: +# +# Since: 8.0 +## +{ 'struct': 'ImageInfoSpecificFileWrapper', + 'data': { 'data': 'ImageInfoSpecificFile' } } + ## # @ImageInfoSpecific: # @@ -199,7 +220,8 @@ 'qcow2': 'ImageInfoSpecificQCow2Wrapper', 'vmdk': 'ImageInfoSpecificVmdkWrapper', 'luks': 'ImageInfoSpecificLUKSWrapper', - 'rbd': 'ImageInfoSpecificRbdWrapper' + 'rbd': 'ImageInfoSpecificRbdWrapper', + 'file': 'ImageInfoSpecificFileWrapper' } } ## From 456e75171a85c19a5bfa202eefcbdc4ef1692f05 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:55 +0200 Subject: [PATCH 339/814] block/vmdk: Change extent info type VMDK's implementation of .bdrv_get_specific_info() returns information about its extent files, ostensibly in the form of ImageInfo objects. However, it does not get this information through bdrv_query_image_info(), but fills only a select few fields with custom information that does not always match the fields' purposes. For example, @format, which is supposed to be a block driver name, is filled with the extent type, e.g. SPARSE or FLAT. In ImageInfo, @compressed shows whether the data that can be seen in the image is stored in compressed form or not. For example, a compressed qcow2 image will store compressed data in its data file, but when accessing the qcow2 node, you will see normal data. This is not how VMDK uses the @compressed field for its extent files: Instead, it signifies whether accessing the extent file will yield compressed data (which the VMDK driver then (de-)compresses). Create a new structure to represent the extent information. This allows us to clarify the fields' meanings, and it clearly shows that these are not complete ImageInfo objects. (That is, if a user wants an extent file's ImageInfo object, they will need to query it separately, and will not get it from ImageInfoSpecificVmdk.extents.) Note that this removes the last use of ['ImageInfo'] (i.e. an array of ImageInfo objects), so the QAPI generator will no longer generate ImageInfoList by default. However, we use it in qemu-img.c, so we need to create a dummy object to force the generate to create that type, similarly to DummyForceArrays in machine.json (introduced in commit 9f08c8ec73878122ad4b061ed334f0437afaaa32 ("qapi: Lazy creation of array types")). Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-4-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/vmdk.c | 8 ++++---- qapi/block-core.json | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 1bba61ad7d..5b0eae877e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2898,12 +2898,12 @@ static int vmdk_has_zero_init(BlockDriverState *bs) return 1; } -static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) +static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent) { - ImageInfo *info = g_new0(ImageInfo, 1); + VmdkExtentInfo *info = g_new0(VmdkExtentInfo, 1); bdrv_refresh_filename(extent->file->bs); - *info = (ImageInfo){ + *info = (VmdkExtentInfo){ .filename = g_strdup(extent->file->bs->filename), .format = g_strdup(extent->type), .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, @@ -2982,7 +2982,7 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, int i; BDRVVmdkState *s = bs->opaque; ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); - ImageInfoList **tail; + VmdkExtentInfoList **tail; *spec_info = (ImageInfoSpecific){ .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, diff --git a/qapi/block-core.json b/qapi/block-core.json index f5d822cbd6..4b9365167f 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -124,7 +124,33 @@ 'create-type': 'str', 'cid': 'int', 'parent-cid': 'int', - 'extents': ['ImageInfo'] + 'extents': ['VmdkExtentInfo'] + } } + +## +# @VmdkExtentInfo: +# +# Information about a VMDK extent file +# +# @filename: Name of the extent file +# +# @format: Extent type (e.g. FLAT or SPARSE) +# +# @virtual-size: Number of bytes covered by this extent +# +# @cluster-size: Cluster size in bytes (for non-flat extents) +# +# @compressed: Whether this extent contains compressed data +# +# Since: 8.0 +## +{ 'struct': 'VmdkExtentInfo', + 'data': { + 'filename': 'str', + 'format': 'str', + 'virtual-size': 'int', + '*cluster-size': 'int', + '*compressed': 'bool' } } ## @@ -5754,3 +5780,13 @@ 'data': { 'device': 'str', '*id': 'str', '*name': 'str'}, 'returns': 'SnapshotInfo', 'allow-preconfig': true } + +## +# @DummyBlockCoreForceArrays: +# +# Not used by QMP; hack to let us use ImageInfoList internally +# +# Since: 8.0 +## +{ 'struct': 'DummyBlockCoreForceArrays', + 'data': { 'unused-image-info': ['ImageInfo'] } } From a2085f8909377b6df738f6c3f7ee6db4d16da8f7 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:56 +0200 Subject: [PATCH 340/814] block: Split BlockNodeInfo off of ImageInfo ImageInfo sometimes contains flat information, and sometimes it does not. Split off a BlockNodeInfo struct, which only contains information about a single node and has no link to the backing image. We do this so we can extend BlockNodeInfo to a BlockGraphInfo struct, which has links to all child nodes, not just the backing node. It would be strange to base BlockGraphInfo on ImageInfo, because then this extended struct would have two links to the backing node (one in BlockGraphInfo as one of all the child links, and one in ImageInfo). Furthermore, it is quite common to ignore the backing-image field altogether: bdrv_query_image_info() does not set it, and bdrv_image_info_dump() does not evaluate it. That signals that we should have different structs for describing a single node and one that has a link to the backing image. Still, bdrv_query_image_info() and bdrv_image_info_dump() are not changed too much in this patch. Follow-up patches will handle them. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-5-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qapi.c | 86 ++++++++++++++++++++++++++++++++------------ include/block/qapi.h | 3 ++ qapi/block-core.json | 24 +++++++++---- 3 files changed, 85 insertions(+), 28 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index 0551875902..e947562e5d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -238,30 +238,18 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs, } /** - * bdrv_query_image_info: - * @bs: block device to examine - * @p_info: location to store image information - * @errp: location to store error information - * - * Store "flat" image information in @p_info. - * - * "Flat" means it does *not* query backing image information, - * i.e. (*pinfo)->has_backing_image will be set to false and - * (*pinfo)->backing_image to NULL even when the image does in fact have - * a backing image. - * - * @p_info will be set only on success. On error, store error in @errp. + * Helper function for other query info functions. Store information about @bs + * in @info, setting @errp on error. */ -void bdrv_query_image_info(BlockDriverState *bs, - ImageInfo **p_info, - Error **errp) +static void bdrv_do_query_node_info(BlockDriverState *bs, + BlockNodeInfo *info, + Error **errp) { int64_t size; const char *backing_filename; BlockDriverInfo bdi; int ret; Error *err = NULL; - ImageInfo *info; aio_context_acquire(bdrv_get_aio_context(bs)); @@ -274,7 +262,6 @@ void bdrv_query_image_info(BlockDriverState *bs, bdrv_refresh_filename(bs); - info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = size; @@ -295,7 +282,6 @@ void bdrv_query_image_info(BlockDriverState *bs, info->format_specific = bdrv_get_specific_info(bs, &err); if (err) { error_propagate(errp, err); - qapi_free_ImageInfo(info); goto out; } backing_filename = bs->backing_file; @@ -331,16 +317,72 @@ void bdrv_query_image_info(BlockDriverState *bs, break; default: error_propagate(errp, err); - qapi_free_ImageInfo(info); goto out; } - *p_info = info; - out: aio_context_release(bdrv_get_aio_context(bs)); } +/** + * bdrv_query_block_node_info: + * @bs: block node to examine + * @p_info: location to store node information + * @errp: location to store error information + * + * Store image information about @bs in @p_info. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_block_node_info(BlockDriverState *bs, + BlockNodeInfo **p_info, + Error **errp) +{ + BlockNodeInfo *info; + ERRP_GUARD(); + + info = g_new0(BlockNodeInfo, 1); + bdrv_do_query_node_info(bs, info, errp); + if (*errp) { + qapi_free_BlockNodeInfo(info); + return; + } + + *p_info = info; +} + +/** + * bdrv_query_image_info: + * @bs: block node to examine + * @p_info: location to store image information + * @errp: location to store error information + * + * Store "flat" image information in @p_info. + * + * "Flat" means it does *not* query backing image information, + * i.e. (*pinfo)->has_backing_image will be set to false and + * (*pinfo)->backing_image to NULL even when the image does in fact have + * a backing image. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, + Error **errp) +{ + ImageInfo *info; + ERRP_GUARD(); + + info = g_new0(ImageInfo, 1); + bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp); + if (*errp) { + qapi_free_ImageInfo(info); + return; + } + + *p_info = info; +} + /* @p_info will be set only on success. */ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp) diff --git a/include/block/qapi.h b/include/block/qapi.h index 902fec81d5..47a2004a40 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -35,6 +35,9 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, int bdrv_query_snapshot_info_list(BlockDriverState *bs, SnapshotInfoList **p_list, Error **errp); +void bdrv_query_block_node_info(BlockDriverState *bs, + BlockNodeInfo **p_info, + Error **errp); void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, Error **errp); diff --git a/qapi/block-core.json b/qapi/block-core.json index 4b9365167f..7720da0498 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -251,7 +251,7 @@ } } ## -# @ImageInfo: +# @BlockNodeInfo: # # Information about a QEMU image file # @@ -279,22 +279,34 @@ # # @snapshots: list of VM snapshots # -# @backing-image: info of the backing image (since 1.6) -# # @format-specific: structure supplying additional format-specific # information (since 1.7) # -# Since: 1.3 +# Since: 8.0 ## -{ 'struct': 'ImageInfo', +{ 'struct': 'BlockNodeInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', '*actual-size': 'int', 'virtual-size': 'int', '*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool', '*backing-filename': 'str', '*full-backing-filename': 'str', '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'], - '*backing-image': 'ImageInfo', '*format-specific': 'ImageInfoSpecific' } } +## +# @ImageInfo: +# +# Information about a QEMU image file, and potentially its backing image +# +# @backing-image: info of the backing image +# +# Since: 1.3 +## +{ 'struct': 'ImageInfo', + 'base': 'BlockNodeInfo', + 'data': { + '*backing-image': 'ImageInfo' + } } + ## # @ImageCheck: # From b1f4cd1589a16fec02f264a09bd3560e4ccce3c2 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:57 +0200 Subject: [PATCH 341/814] qemu-img: Use BlockNodeInfo qemu-img info never uses ImageInfo's backing-image field, because it opens the backing chain one by one with BDRV_O_NO_BACKING, and prints all backing chain nodes' information consecutively. Use BlockNodeInfo to make it clear that we only print information about a single node, and that we are not using the backing-image field. Notably, bdrv_image_info_dump() does not evaluate the backing-image field, so we can easily make it take a BlockNodeInfo pointer (and consequentially rename it to bdrv_node_info_dump()). It makes more sense this way, because again, the interface now makes it syntactically clear that backing-image is ignored by this function. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-6-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/monitor/block-hmp-cmds.c | 2 +- block/qapi.c | 2 +- include/block/qapi.h | 2 +- qapi/block-core.json | 4 +-- qemu-img.c | 48 +++++++++++++++++----------------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index 0ff7c84039..d6eaacdb12 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -725,7 +725,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, monitor_printf(mon, "\nImages:\n"); image_info = inserted->image; while (1) { - bdrv_image_info_dump(image_info); + bdrv_node_info_dump(qapi_ImageInfo_base(image_info)); if (image_info->backing_image) { image_info = image_info->backing_image; } else { diff --git a/block/qapi.c b/block/qapi.c index e947562e5d..e8926c992b 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -848,7 +848,7 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, visit_free(v); } -void bdrv_image_info_dump(ImageInfo *info) +void bdrv_node_info_dump(BlockNodeInfo *info) { char *size_buf, *dsize_buf; if (!info->has_actual_size) { diff --git a/include/block/qapi.h b/include/block/qapi.h index 47a2004a40..7e58903c20 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -45,5 +45,5 @@ void bdrv_query_image_info(BlockDriverState *bs, void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, const char *prefix); -void bdrv_image_info_dump(ImageInfo *info); +void bdrv_node_info_dump(BlockNodeInfo *info); #endif diff --git a/qapi/block-core.json b/qapi/block-core.json index 7720da0498..4cf2deeb6c 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -5796,9 +5796,9 @@ ## # @DummyBlockCoreForceArrays: # -# Not used by QMP; hack to let us use ImageInfoList internally +# Not used by QMP; hack to let us use BlockNodeInfoList internally # # Since: 8.0 ## { 'struct': 'DummyBlockCoreForceArrays', - 'data': { 'unused-image-info': ['ImageInfo'] } } + 'data': { 'unused-block-node-info': ['BlockNodeInfo'] } } diff --git a/qemu-img.c b/qemu-img.c index 5bb63c5e0c..a2d414b3c2 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2817,13 +2817,13 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } -static void dump_json_image_info_list(ImageInfoList *list) +static void dump_json_block_node_info_list(BlockNodeInfoList *list) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfoList(v, NULL, &list, &error_abort); + visit_type_BlockNodeInfoList(v, NULL, &list, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2833,13 +2833,13 @@ static void dump_json_image_info_list(ImageInfoList *list) g_string_free(str, true); } -static void dump_json_image_info(ImageInfo *info) +static void dump_json_block_node_info(BlockNodeInfo *info) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfo(v, NULL, &info, &error_abort); + visit_type_BlockNodeInfo(v, NULL, &info, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2849,9 +2849,9 @@ static void dump_json_image_info(ImageInfo *info) g_string_free(str, true); } -static void dump_human_image_info_list(ImageInfoList *list) +static void dump_human_image_info_list(BlockNodeInfoList *list) { - ImageInfoList *elem; + BlockNodeInfoList *elem; bool delim = false; for (elem = list; elem; elem = elem->next) { @@ -2860,7 +2860,7 @@ static void dump_human_image_info_list(ImageInfoList *list) } delim = true; - bdrv_image_info_dump(elem->value); + bdrv_node_info_dump(elem->value); } } @@ -2870,24 +2870,24 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) } /** - * Open an image file chain and return an ImageInfoList + * Open an image file chain and return an BlockNodeInfoList * * @filename: topmost image filename * @fmt: topmost image format (may be NULL to autodetect) * @chain: true - enumerate entire backing file chain * false - only topmost image file * - * Returns a list of ImageInfo objects or NULL if there was an error opening an - * image file. If there was an error a message will have been printed to - * stderr. + * Returns a list of BlockNodeInfo objects or NULL if there was an error + * opening an image file. If there was an error a message will have been + * printed to stderr. */ -static ImageInfoList *collect_image_info_list(bool image_opts, - const char *filename, - const char *fmt, - bool chain, bool force_share) +static BlockNodeInfoList *collect_image_info_list(bool image_opts, + const char *filename, + const char *fmt, + bool chain, bool force_share) { - ImageInfoList *head = NULL; - ImageInfoList **tail = &head; + BlockNodeInfoList *head = NULL; + BlockNodeInfoList **tail = &head; GHashTable *filenames; Error *err = NULL; @@ -2896,7 +2896,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, while (filename) { BlockBackend *blk; BlockDriverState *bs; - ImageInfo *info; + BlockNodeInfo *info; if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { error_report("Backing file '%s' creates an infinite loop.", @@ -2913,7 +2913,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, } bs = blk_bs(blk); - bdrv_query_image_info(bs, &info, &err); + bdrv_query_block_node_info(bs, &info, &err); if (err) { error_report_err(err); blk_unref(blk); @@ -2946,7 +2946,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, return head; err: - qapi_free_ImageInfoList(head); + qapi_free_BlockNodeInfoList(head); g_hash_table_destroy(filenames); return NULL; } @@ -2957,7 +2957,7 @@ static int img_info(int argc, char **argv) OutputFormat output_format = OFORMAT_HUMAN; bool chain = false; const char *filename, *fmt, *output; - ImageInfoList *list; + BlockNodeInfoList *list; bool image_opts = false; bool force_share = false; @@ -3036,14 +3036,14 @@ static int img_info(int argc, char **argv) break; case OFORMAT_JSON: if (chain) { - dump_json_image_info_list(list); + dump_json_block_node_info_list(list); } else { - dump_json_image_info(list->value); + dump_json_block_node_info(list->value); } break; } - qapi_free_ImageInfoList(list); + qapi_free_BlockNodeInfoList(list); return 0; } From 5d8813593f3f673fc96eed199beb35690cc46f58 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:58 +0200 Subject: [PATCH 342/814] block/qapi: Let bdrv_query_image_info() recurse There is no real reason why bdrv_query_image_info() should generally not recurse. The ImageInfo struct has a pointer to the backing image, so it should generally be filled, unless the caller explicitly opts out. This moves the recursing code from bdrv_block_device_info() into bdrv_query_image_info(). Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-7-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qapi.c | 92 +++++++++++++++++++++++++++----------------- include/block/qapi.h | 2 + 2 files changed, 58 insertions(+), 36 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index e8926c992b..9a977aaa9b 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -48,8 +48,10 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, Error **errp) { ImageInfo **p_image_info; + ImageInfo *backing_info; BlockDriverState *bs0, *backing; BlockDeviceInfo *info; + ERRP_GUARD(); if (!bs->drv) { error_setg(errp, "Block device %s is ejected", bs->node_name); @@ -147,37 +149,21 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, bs0 = bs; p_image_info = &info->image; info->backing_file_depth = 0; - while (1) { - Error *local_err = NULL; - bdrv_query_image_info(bs0, p_image_info, &local_err); - if (local_err) { - error_propagate(errp, local_err); - qapi_free_BlockDeviceInfo(info); - return NULL; - } - /* stop gathering data for flat output */ - if (flat) { - break; - } + /* + * Skip automatically inserted nodes that the user isn't aware of for + * query-block (blk != NULL), but not for query-named-block-nodes + */ + bdrv_query_image_info(bs0, p_image_info, flat, blk != NULL, errp); + if (*errp) { + qapi_free_BlockDeviceInfo(info); + return NULL; + } - if (bs0->drv && bdrv_filter_or_cow_child(bs0)) { - /* - * Put any filtered child here (for backwards compatibility to when - * we put bs0->backing here, which might be any filtered child). - */ - info->backing_file_depth++; - bs0 = bdrv_filter_or_cow_bs(bs0); - p_image_info = &((*p_image_info)->backing_image); - } else { - break; - } - - /* Skip automatically inserted nodes that the user isn't aware of for - * query-block (blk != NULL), but not for query-named-block-nodes */ - if (blk) { - bs0 = bdrv_skip_implicit_filters(bs0); - } + backing_info = info->image->backing_image; + while (backing_info) { + info->backing_file_depth++; + backing_info = backing_info->backing_image; } return info; @@ -355,19 +341,28 @@ void bdrv_query_block_node_info(BlockDriverState *bs, * bdrv_query_image_info: * @bs: block node to examine * @p_info: location to store image information + * @flat: skip backing node information + * @skip_implicit_filters: skip implicit filters in the backing chain * @errp: location to store error information * - * Store "flat" image information in @p_info. + * Store image information in @p_info, potentially recursively covering the + * backing chain. * - * "Flat" means it does *not* query backing image information, - * i.e. (*pinfo)->has_backing_image will be set to false and - * (*pinfo)->backing_image to NULL even when the image does in fact have - * a backing image. + * If @flat is true, do not query backing image information, i.e. + * (*p_info)->has_backing_image will be set to false and + * (*p_info)->backing_image to NULL even when the image does in fact have a + * backing image. + * + * If @skip_implicit_filters is true, implicit filter nodes in the backing chain + * will be skipped when querying backing image information. + * (@skip_implicit_filters is ignored when @flat is true.) * * @p_info will be set only on success. On error, store error in @errp. */ void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, + bool flat, + bool skip_implicit_filters, Error **errp) { ImageInfo *info; @@ -376,11 +371,36 @@ void bdrv_query_image_info(BlockDriverState *bs, info = g_new0(ImageInfo, 1); bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp); if (*errp) { - qapi_free_ImageInfo(info); - return; + goto fail; + } + + if (!flat) { + BlockDriverState *backing; + + /* + * Use any filtered child here (for backwards compatibility to when + * we always took bs->backing, which might be any filtered child). + */ + backing = bdrv_filter_or_cow_bs(bs); + if (skip_implicit_filters) { + backing = bdrv_skip_implicit_filters(backing); + } + + if (backing) { + bdrv_query_image_info(backing, &info->backing_image, false, + skip_implicit_filters, errp); + if (*errp) { + goto fail; + } + } } *p_info = info; + return; + +fail: + assert(*errp); + qapi_free_ImageInfo(info); } /* @p_info will be set only on success. */ diff --git a/include/block/qapi.h b/include/block/qapi.h index 7e58903c20..ff8fb8a764 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -40,6 +40,8 @@ void bdrv_query_block_node_info(BlockDriverState *bs, Error **errp); void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, + bool flat, + bool skip_implicit_filters, Error **errp); void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); From 6cab33997b91eb86e82a6a2ae58a24f835249d4a Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:26:59 +0200 Subject: [PATCH 343/814] block/qapi: Introduce BlockGraphInfo Introduce a new QAPI type BlockGraphInfo and an associated bdrv_query_block_graph_info() function that recursively gathers BlockNodeInfo objects through a block graph. A follow-up patch is going to make "qemu-img info" use this to print information about all nodes that are (usually implicitly) opened for a given image file. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-8-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qapi.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ include/block/qapi.h | 3 +++ qapi/block-core.json | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/block/qapi.c b/block/qapi.c index 9a977aaa9b..335d5b9e10 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -403,6 +403,54 @@ fail: qapi_free_ImageInfo(info); } +/** + * bdrv_query_block_graph_info: + * @bs: root node to start from + * @p_info: location to store image information + * @errp: location to store error information + * + * Store image information about the graph starting from @bs in @p_info. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_block_graph_info(BlockDriverState *bs, + BlockGraphInfo **p_info, + Error **errp) +{ + BlockGraphInfo *info; + BlockChildInfoList **children_list_tail; + BdrvChild *c; + ERRP_GUARD(); + + info = g_new0(BlockGraphInfo, 1); + bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp); + if (*errp) { + goto fail; + } + + children_list_tail = &info->children; + + QLIST_FOREACH(c, &bs->children, next) { + BlockChildInfo *c_info; + + c_info = g_new0(BlockChildInfo, 1); + QAPI_LIST_APPEND(children_list_tail, c_info); + + c_info->name = g_strdup(c->name); + bdrv_query_block_graph_info(c->bs, &c_info->info, errp); + if (*errp) { + goto fail; + } + } + + *p_info = info; + return; + +fail: + assert(*errp != NULL); + qapi_free_BlockGraphInfo(info); +} + /* @p_info will be set only on success. */ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp) diff --git a/include/block/qapi.h b/include/block/qapi.h index ff8fb8a764..685e7c2648 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -43,6 +43,9 @@ void bdrv_query_image_info(BlockDriverState *bs, bool flat, bool skip_implicit_filters, Error **errp); +void bdrv_query_block_graph_info(BlockDriverState *bs, + BlockGraphInfo **p_info, + Error **errp); void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, diff --git a/qapi/block-core.json b/qapi/block-core.json index 4cf2deeb6c..d703e0fb16 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -307,6 +307,41 @@ '*backing-image': 'ImageInfo' } } +## +# @BlockChildInfo: +# +# Information about all nodes in the block graph starting at some node, +# annotated with information about that node in relation to its parent. +# +# @name: Child name of the root node in the BlockGraphInfo struct, in its role +# as the child of some undescribed parent node +# +# @info: Block graph information starting at this node +# +# Since: 8.0 +## +{ 'struct': 'BlockChildInfo', + 'data': { + 'name': 'str', + 'info': 'BlockGraphInfo' + } } + +## +# @BlockGraphInfo: +# +# Information about all nodes in a block (sub)graph in the form of BlockNodeInfo +# data. +# The base BlockNodeInfo struct contains the information for the (sub)graph's +# root node. +# +# @children: Array of links to this node's child nodes' information +# +# Since: 8.0 +## +{ 'struct': 'BlockGraphInfo', + 'base': 'BlockNodeInfo', + 'data': { 'children': ['BlockChildInfo'] } } + ## # @ImageCheck: # From 76c9e9750d1bd580e8ed4465f6be3a986434e7c3 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:27:00 +0200 Subject: [PATCH 344/814] block/qapi: Add indentation to bdrv_node_info_dump() In order to let qemu-img info present a block graph, add a parameter to bdrv_node_info_dump() and bdrv_image_info_specific_dump() so that the information of nodes below the root level can be given an indentation. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-9-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/monitor/block-hmp-cmds.c | 2 +- block/qapi.c | 47 +++++++++++++++++++--------------- include/block/qapi.h | 5 ++-- qemu-img.c | 2 +- qemu-io-cmds.c | 3 ++- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index d6eaacdb12..4b441ac468 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -725,7 +725,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, monitor_printf(mon, "\nImages:\n"); image_info = inserted->image; while (1) { - bdrv_node_info_dump(qapi_ImageInfo_base(image_info)); + bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0); if (image_info->backing_image) { image_info = image_info->backing_image; } else { diff --git a/block/qapi.c b/block/qapi.c index 335d5b9e10..c6d46ee2e4 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -898,7 +898,8 @@ static bool qobject_is_empty_dump(const QObject *obj) * prepending an optional prefix if the dump is not empty. */ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, - const char *prefix) + const char *prefix, + int indentation) { QObject *obj, *data; Visitor *v = qobject_output_visitor_new(&obj); @@ -908,48 +909,51 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, data = qdict_get(qobject_to(QDict, obj), "data"); if (!qobject_is_empty_dump(data)) { if (prefix) { - qemu_printf("%s", prefix); + qemu_printf("%*s%s", indentation * 4, "", prefix); } - dump_qobject(1, data); + dump_qobject(indentation + 1, data); } qobject_unref(obj); visit_free(v); } -void bdrv_node_info_dump(BlockNodeInfo *info) +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation) { char *size_buf, *dsize_buf; + g_autofree char *ind_s = g_strdup_printf("%*s", indentation * 4, ""); + if (!info->has_actual_size) { dsize_buf = g_strdup("unavailable"); } else { dsize_buf = size_to_str(info->actual_size); } size_buf = size_to_str(info->virtual_size); - qemu_printf("image: %s\n" - "file format: %s\n" - "virtual size: %s (%" PRId64 " bytes)\n" - "disk size: %s\n", - info->filename, info->format, size_buf, - info->virtual_size, - dsize_buf); + qemu_printf("%simage: %s\n" + "%sfile format: %s\n" + "%svirtual size: %s (%" PRId64 " bytes)\n" + "%sdisk size: %s\n", + ind_s, info->filename, + ind_s, info->format, + ind_s, size_buf, info->virtual_size, + ind_s, dsize_buf); g_free(size_buf); g_free(dsize_buf); if (info->has_encrypted && info->encrypted) { - qemu_printf("encrypted: yes\n"); + qemu_printf("%sencrypted: yes\n", ind_s); } if (info->has_cluster_size) { - qemu_printf("cluster_size: %" PRId64 "\n", - info->cluster_size); + qemu_printf("%scluster_size: %" PRId64 "\n", + ind_s, info->cluster_size); } if (info->has_dirty_flag && info->dirty_flag) { - qemu_printf("cleanly shut down: no\n"); + qemu_printf("%scleanly shut down: no\n", ind_s); } if (info->backing_filename) { - qemu_printf("backing file: %s", info->backing_filename); + qemu_printf("%sbacking file: %s", ind_s, info->backing_filename); if (!info->full_backing_filename) { qemu_printf(" (cannot determine actual path)"); } else if (strcmp(info->backing_filename, @@ -958,15 +962,16 @@ void bdrv_node_info_dump(BlockNodeInfo *info) } qemu_printf("\n"); if (info->backing_filename_format) { - qemu_printf("backing file format: %s\n", - info->backing_filename_format); + qemu_printf("%sbacking file format: %s\n", + ind_s, info->backing_filename_format); } } if (info->has_snapshots) { SnapshotInfoList *elem; - qemu_printf("Snapshot list:\n"); + qemu_printf("%sSnapshot list:\n", ind_s); + qemu_printf("%s", ind_s); bdrv_snapshot_dump(NULL); qemu_printf("\n"); @@ -986,6 +991,7 @@ void bdrv_node_info_dump(BlockNodeInfo *info) pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); pstrcpy(sn.name, sizeof(sn.name), elem->value->name); + qemu_printf("%s", ind_s); bdrv_snapshot_dump(&sn); qemu_printf("\n"); } @@ -993,6 +999,7 @@ void bdrv_node_info_dump(BlockNodeInfo *info) if (info->format_specific) { bdrv_image_info_specific_dump(info->format_specific, - "Format specific information:\n"); + "Format specific information:\n", + indentation); } } diff --git a/include/block/qapi.h b/include/block/qapi.h index 685e7c2648..aa59880330 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -49,6 +49,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs, void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, - const char *prefix); -void bdrv_node_info_dump(BlockNodeInfo *info); + const char *prefix, + int indentation); +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation); #endif diff --git a/qemu-img.c b/qemu-img.c index a2d414b3c2..d2763ac2de 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2860,7 +2860,7 @@ static void dump_human_image_info_list(BlockNodeInfoList *list) } delim = true; - bdrv_node_info_dump(elem->value); + bdrv_node_info_dump(elem->value, 0); } } diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index d7e562dda6..a061031615 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -1789,7 +1789,8 @@ static int info_f(BlockBackend *blk, int argc, char **argv) } if (spec_info) { bdrv_image_info_specific_dump(spec_info, - "Format specific information:\n"); + "Format specific information:\n", + 0); qapi_free_ImageInfoSpecific(spec_info); } From bcc6777ad6facede73c0cf8b1700045bf4365f7d Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:27:01 +0200 Subject: [PATCH 345/814] iotests: Filter child node information Before we let qemu-img info print child node information, have common.filter, common.rc, and iotests.py filter it from the test output so we get as few reference output changes as possible. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-10-hreitz@redhat.com> Tested-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/common.filter | 22 ++++++++++++++-------- tests/qemu-iotests/common.rc | 22 ++++++++++++++-------- tests/qemu-iotests/iotests.py | 18 +++++++++++++++--- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index cc9f1a5891..6b32c7fbfa 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -223,6 +223,7 @@ _filter_img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' + regex_json_child_start='^ *"children": \[' gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ @@ -251,20 +252,25 @@ _filter_img_info() -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \ -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \ while IFS='' read -r line; do - if [[ $format_specific == 1 ]]; then - discard=0 - elif [[ $line == "Format specific information:" ]]; then - discard=1 - elif [[ $line =~ $regex_json_spec_start ]]; then - discard=2 - regex_json_spec_end="^${line%%[^ ]*}\\},? *$" + if [[ $discard == 0 ]]; then + if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then + discard=1 + elif [[ $line =~ "Child node '/" ]]; then + discard=1 + elif [[ $line =~ $regex_json_spec_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\},? *$" + elif [[ $line =~ $regex_json_child_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\],? *$" + fi fi if [[ $discard == 0 ]]; then echo "$line" elif [[ $discard == 1 && ! $line ]]; then echo discard=0 - elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then + elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then discard=0 fi done diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index db757025cb..f4476b62f7 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -711,6 +711,7 @@ _img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' + regex_json_child_start='^ *"children": \[' $QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \ sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ @@ -721,20 +722,25 @@ _img_info() -e "/^disk size:/ D" \ -e "/actual-size/ D" | \ while IFS='' read -r line; do - if [[ $format_specific == 1 ]]; then - discard=0 - elif [[ $line == "Format specific information:" ]]; then - discard=1 - elif [[ $line =~ $regex_json_spec_start ]]; then - discard=2 - regex_json_spec_end="^${line%%[^ ]*}\\},? *$" + if [[ $discard == 0 ]]; then + if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then + discard=1 + elif [[ $line =~ "Child node '/" ]]; then + discard=1 + elif [[ $format_specific == 0 && $line =~ $regex_json_spec_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\},? *$" + elif [[ $line =~ $regex_json_child_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\],? *$" + fi fi if [[ $discard == 0 ]]; then echo "$line" elif [[ $discard == 1 && ! $line ]]; then echo discard=0 - elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then + elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then discard=0 fi done diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index da7d6637e1..94aeb3f3b2 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -329,7 +329,7 @@ def qemu_img_log(*args: str, check: bool = True def img_info_log(filename: str, filter_path: Optional[str] = None, use_image_opts: bool = False, extra_args: Sequence[str] = (), - check: bool = True, + check: bool = True, drop_child_info: bool = True, ) -> None: args = ['info'] if use_image_opts: @@ -342,7 +342,7 @@ def img_info_log(filename: str, filter_path: Optional[str] = None, output = qemu_img(*args, check=check).stdout if not filter_path: filter_path = filename - log(filter_img_info(output, filter_path)) + log(filter_img_info(output, filter_path, drop_child_info)) def qemu_io_wrap_args(args: Sequence[str]) -> List[str]: if '-f' in args or '--image-opts' in args: @@ -642,11 +642,23 @@ def filter_qmp_virtio_scsi(qmsg): def filter_generated_node_ids(msg): return re.sub("#block[0-9]+", "NODE_NAME", msg) -def filter_img_info(output, filename): +def filter_img_info(output: str, filename: str, + drop_child_info: bool = True) -> str: lines = [] + drop_indented = False for line in output.split('\n'): if 'disk size' in line or 'actual-size' in line: continue + + # Drop child node info + if drop_indented: + if line.startswith(' '): + continue + drop_indented = False + if drop_child_info and "Child node '/" in line: + drop_indented = True + continue + line = line.replace(filename, 'TEST_IMG') line = filter_testfiles(line) line = line.replace(imgfmt, 'IMGFMT') From 74163adda3101b127943f7cbbf8fcccd2d472426 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:27:02 +0200 Subject: [PATCH 346/814] iotests/106, 214, 308: Read only one size line These tests read size information (sometimes disk size, sometimes virtual size) from qemu-img info's output. Once qemu-img starts printing info about child nodes, we are going to see multiple instances of that per image, but these tests are only interested in the first one, so use "head -n 1" to get it. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-11-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/106 | 4 ++-- tests/qemu-iotests/214 | 6 ++++-- tests/qemu-iotests/308 | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index 9d6adb542d..ae0fc46691 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -66,7 +66,7 @@ for create_mode in off falloc full; do expected_size=$((expected_size + $GROWTH_SIZE)) fi - actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') + actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') # The actual size may exceed the expected size, depending on the file @@ -105,7 +105,7 @@ for growth_mode in falloc full; do _make_test_img -o "extent_size_hint=0" 2G $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K - actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') + actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') if [ $actual_size -lt $GROWTH_SIZE ]; then diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 index c66e246ba2..55ffcd7f44 100755 --- a/tests/qemu-iotests/214 +++ b/tests/qemu-iotests/214 @@ -102,7 +102,8 @@ let data_size="8 * $cluster_size" $QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \ 2>&1 | _filter_qemu_io | _filter_testdir sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" | - sed -n '/"actual-size":/ s/[^0-9]//gp') + sed -n '/"actual-size":/ s/[^0-9]//gp' | + head -n 1) _make_test_img 2M -o cluster_size=$cluster_size echo "Write compressed data:" @@ -124,7 +125,8 @@ $QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\ _filter_qemu_io | _filter_testdir sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" | - sed -n '/"actual-size":/ s/[^0-9]//gp') + sed -n '/"actual-size":/ s/[^0-9]//gp' | + head -n 1) if [ $sizeA -lt $sizeB ] then diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index bde4aac2fa..09275e9a10 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -217,12 +217,12 @@ echo echo '=== Remove export ===' # Double-check that $EXT_MP appears as a non-empty file (the raw image) -$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' +$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 fuse_export_del 'export-mp' # See that the file appears empty again -$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' +$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 echo echo '=== Writable export ===' From c04d0ab026201d21873a63f768cb69c4554dfec1 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:27:03 +0200 Subject: [PATCH 347/814] qemu-img: Let info print block graph For every node in the backing chain, collect its BlockGraphInfo struct using bdrv_query_block_graph_info(). Print all nodes' information, indenting child nodes and labelling them with a path constructed from the child names leading to the node from the root (e.g. /file/file). Note that we open each image with BDRV_O_NO_BACKING, so its backing child is omitted from this graph, and thus presented in the previous manner: By simply concatenating all images' information, separated with blank lines. This affects two iotests: - 065: Here we try to get the format node's format specific information. The pre-patch code does so by taking all lines from "Format specific information:" until an empty line. This format specific information is no longer followed by an empty line, though, but by child node information, so limit the range by "Child node '/file':". - 302: Calls qemu_img() for qemu-img info directly, which does not filter the output, so the child node information ends up in the output. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-12-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- qapi/block-core.json | 4 +-- qemu-img.c | 69 ++++++++++++++++++++++++++------------ tests/qemu-iotests/065 | 2 +- tests/qemu-iotests/302.out | 5 +++ 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index d703e0fb16..7f331eb8ea 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -5831,9 +5831,9 @@ ## # @DummyBlockCoreForceArrays: # -# Not used by QMP; hack to let us use BlockNodeInfoList internally +# Not used by QMP; hack to let us use BlockGraphInfoList internally # # Since: 8.0 ## { 'struct': 'DummyBlockCoreForceArrays', - 'data': { 'unused-block-node-info': ['BlockNodeInfo'] } } + 'data': { 'unused-block-graph-info': ['BlockGraphInfo'] } } diff --git a/qemu-img.c b/qemu-img.c index d2763ac2de..595179a346 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2817,13 +2817,13 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } -static void dump_json_block_node_info_list(BlockNodeInfoList *list) +static void dump_json_block_graph_info_list(BlockGraphInfoList *list) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_BlockNodeInfoList(v, NULL, &list, &error_abort); + visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2833,13 +2833,13 @@ static void dump_json_block_node_info_list(BlockNodeInfoList *list) g_string_free(str, true); } -static void dump_json_block_node_info(BlockNodeInfo *info) +static void dump_json_block_graph_info(BlockGraphInfo *info) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_BlockNodeInfo(v, NULL, &info, &error_abort); + visit_type_BlockGraphInfo(v, NULL, &info, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2849,9 +2849,29 @@ static void dump_json_block_node_info(BlockNodeInfo *info) g_string_free(str, true); } -static void dump_human_image_info_list(BlockNodeInfoList *list) +static void dump_human_image_info(BlockGraphInfo *info, int indentation, + const char *path) { - BlockNodeInfoList *elem; + BlockChildInfoList *children_list; + + bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation); + + for (children_list = info->children; children_list; + children_list = children_list->next) + { + BlockChildInfo *child = children_list->value; + g_autofree char *child_path = NULL; + + printf("%*sChild node '%s%s':\n", + indentation * 4, "", path, child->name); + child_path = g_strdup_printf("%s%s/", path, child->name); + dump_human_image_info(child->info, indentation + 1, child_path); + } +} + +static void dump_human_image_info_list(BlockGraphInfoList *list) +{ + BlockGraphInfoList *elem; bool delim = false; for (elem = list; elem; elem = elem->next) { @@ -2860,7 +2880,7 @@ static void dump_human_image_info_list(BlockNodeInfoList *list) } delim = true; - bdrv_node_info_dump(elem->value, 0); + dump_human_image_info(elem->value, 0, "/"); } } @@ -2870,7 +2890,7 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) } /** - * Open an image file chain and return an BlockNodeInfoList + * Open an image file chain and return an BlockGraphInfoList * * @filename: topmost image filename * @fmt: topmost image format (may be NULL to autodetect) @@ -2881,13 +2901,13 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) * opening an image file. If there was an error a message will have been * printed to stderr. */ -static BlockNodeInfoList *collect_image_info_list(bool image_opts, - const char *filename, - const char *fmt, - bool chain, bool force_share) +static BlockGraphInfoList *collect_image_info_list(bool image_opts, + const char *filename, + const char *fmt, + bool chain, bool force_share) { - BlockNodeInfoList *head = NULL; - BlockNodeInfoList **tail = &head; + BlockGraphInfoList *head = NULL; + BlockGraphInfoList **tail = &head; GHashTable *filenames; Error *err = NULL; @@ -2896,7 +2916,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, while (filename) { BlockBackend *blk; BlockDriverState *bs; - BlockNodeInfo *info; + BlockGraphInfo *info; if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { error_report("Backing file '%s' creates an infinite loop.", @@ -2913,7 +2933,14 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, } bs = blk_bs(blk); - bdrv_query_block_node_info(bs, &info, &err); + /* + * Note that the returned BlockGraphInfo object will not have + * information about this image's backing node, because we have opened + * it with BDRV_O_NO_BACKING. Printing this object will therefore not + * duplicate the backing chain information that we obtain by walking + * the chain manually here. + */ + bdrv_query_block_graph_info(bs, &info, &err); if (err) { error_report_err(err); blk_unref(blk); @@ -2946,7 +2973,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, return head; err: - qapi_free_BlockNodeInfoList(head); + qapi_free_BlockGraphInfoList(head); g_hash_table_destroy(filenames); return NULL; } @@ -2957,7 +2984,7 @@ static int img_info(int argc, char **argv) OutputFormat output_format = OFORMAT_HUMAN; bool chain = false; const char *filename, *fmt, *output; - BlockNodeInfoList *list; + BlockGraphInfoList *list; bool image_opts = false; bool force_share = false; @@ -3036,14 +3063,14 @@ static int img_info(int argc, char **argv) break; case OFORMAT_JSON: if (chain) { - dump_json_block_node_info_list(list); + dump_json_block_graph_info_list(list); } else { - dump_json_block_node_info(list->value); + dump_json_block_graph_info(list->value); } break; } - qapi_free_BlockNodeInfoList(list); + qapi_free_BlockGraphInfoList(list); return 0; } diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index b724c89c7c..b76701c71e 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -56,7 +56,7 @@ class TestQemuImgInfo(TestImageInfoSpecific): def test_human(self): data = qemu_img('info', '--output=human', test_img).stdout.split('\n') data = data[(data.index('Format specific information:') + 1) - :data.index('')] + :data.index("Child node '/file':")] for field in data: self.assertTrue(re.match('^ {4}[^ ]', field) is not None) data = [line.strip() for line in data] diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out index 3e7c281b91..edfa1c4f05 100644 --- a/tests/qemu-iotests/302.out +++ b/tests/qemu-iotests/302.out @@ -4,6 +4,11 @@ image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock file format: raw virtual size: 448 KiB (458752 bytes) disk size: unavailable +Child node '/file': + image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock + file format: nbd + virtual size: 448 KiB (458752 bytes) + disk size: unavailable === Converted image info === image: TEST_IMG From d570177b50c389f379f93183155a27d44856ab46 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Mon, 20 Jun 2022 18:27:04 +0200 Subject: [PATCH 348/814] qemu-img: Change info key names for protocol nodes Currently, when querying a qcow2 image, qemu-img info reports something like this: image: test.qcow2 file format: qcow2 virtual size: 64 MiB (67108864 bytes) disk size: 196 KiB cluster_size: 65536 Format specific information: compat: 1.1 compression type: zlib lazy refcounts: false refcount bits: 16 corrupt: false extended l2: false Child node '/file': image: test.qcow2 file format: file virtual size: 192 KiB (197120 bytes) disk size: 196 KiB Format specific information: extent size hint: 1048576 Notably, the way the keys are named is specific for image files: The filename is shown under "image", the BDS driver under "file format", and the BDS length under "virtual size". This does not make much sense for nodes that are not actually supposed to be guest images, like the /file child node shown above. Give bdrv_node_info_dump() a @protocol parameter that gives a hint that the respective node is probably just used for data storage and does not necessarily present the data for a VM guest disk. This renames the keys so that with this patch, the output becomes: image: test.qcow2 [...] Child node '/file': filename: test.qcow2 protocol type: file file length: 192 KiB (197120 bytes) disk size: 196 KiB Format specific information: extent size hint: 1048576 (Perhaps we should also rename "Format specific information", but I could not come up with anything better that will not become problematic if we guess wrong with the protocol "heuristic".) This change affects iotest 302, which has protocol node information in its reference output. Signed-off-by: Hanna Reitz Message-Id: <20220620162704.80987-13-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/monitor/block-hmp-cmds.c | 2 +- block/qapi.c | 39 ++++++++++++++++++++++++++++------ include/block/qapi.h | 2 +- qemu-img.c | 3 ++- tests/qemu-iotests/302.out | 6 +++--- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index 4b441ac468..4dc07f71d4 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -725,7 +725,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, monitor_printf(mon, "\nImages:\n"); image_info = inserted->image; while (1) { - bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0); + bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0, false); if (image_info->backing_image) { image_info = image_info->backing_image; } else { diff --git a/block/qapi.c b/block/qapi.c index c6d46ee2e4..d52f1ab614 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -917,24 +917,49 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, visit_free(v); } -void bdrv_node_info_dump(BlockNodeInfo *info, int indentation) +/** + * Print the given @info object in human-readable form. Every field is indented + * using the given @indentation (four spaces per indentation level). + * + * When using this to print a whole block graph, @protocol can be set to true to + * signify that the given information is associated with a protocol node, i.e. + * just data storage for an image, such that the data it presents is not really + * a full VM disk. If so, several fields change name: For example, "virtual + * size" is printed as "file length". + * (Consider a qcow2 image, which is represented by a qcow2 node and a file + * node. Printing a "virtual size" for the file node does not make sense, + * because without the qcow2 node, it is not really a guest disk, so it does not + * have a "virtual size". Therefore, we call it "file length" instead.) + * + * @protocol is ignored when @indentation is 0, because we take that to mean + * that the associated node is the root node in the queried block graph, and + * thus is always to be interpreted as a standalone guest disk. + */ +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol) { char *size_buf, *dsize_buf; g_autofree char *ind_s = g_strdup_printf("%*s", indentation * 4, ""); + if (indentation == 0) { + /* Top level, consider this a normal image */ + protocol = false; + } + if (!info->has_actual_size) { dsize_buf = g_strdup("unavailable"); } else { dsize_buf = size_to_str(info->actual_size); } size_buf = size_to_str(info->virtual_size); - qemu_printf("%simage: %s\n" - "%sfile format: %s\n" - "%svirtual size: %s (%" PRId64 " bytes)\n" + qemu_printf("%s%s: %s\n" + "%s%s: %s\n" + "%s%s: %s (%" PRId64 " bytes)\n" "%sdisk size: %s\n", - ind_s, info->filename, - ind_s, info->format, - ind_s, size_buf, info->virtual_size, + ind_s, protocol ? "filename" : "image", info->filename, + ind_s, protocol ? "protocol type" : "file format", + info->format, + ind_s, protocol ? "file length" : "virtual size", + size_buf, info->virtual_size, ind_s, dsize_buf); g_free(size_buf); g_free(dsize_buf); diff --git a/include/block/qapi.h b/include/block/qapi.h index aa59880330..8773b9b191 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -51,5 +51,5 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, const char *prefix, int indentation); -void bdrv_node_info_dump(BlockNodeInfo *info, int indentation); +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol); #endif diff --git a/qemu-img.c b/qemu-img.c index 595179a346..7c05931866 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2854,7 +2854,8 @@ static void dump_human_image_info(BlockGraphInfo *info, int indentation, { BlockChildInfoList *children_list; - bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation); + bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation, + info->children == NULL); for (children_list = info->children; children_list; children_list = children_list->next) diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out index edfa1c4f05..7b5014cdd8 100644 --- a/tests/qemu-iotests/302.out +++ b/tests/qemu-iotests/302.out @@ -5,9 +5,9 @@ file format: raw virtual size: 448 KiB (458752 bytes) disk size: unavailable Child node '/file': - image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock - file format: nbd - virtual size: 448 KiB (458752 bytes) + filename: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock + protocol type: nbd + file length: 448 KiB (458752 bytes) disk size: unavailable === Converted image info === From 69c4befba15ff5ace7408e0f107c38c699c294a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:00:53 +0000 Subject: [PATCH 349/814] scripts/ci: update gitlab-runner playbook to use latest runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were using quite and old runner on our machines and running into issues with stalling jobs. Gitlab in the meantime now reliably provide the latest packaged versions of the runner under a stable URL. This update: - creates a per-arch subdir for builds - switches from binary tarballs to deb packages - re-uses the same binary for the secondary runner - updates distro check for second to 22.04 Note this script isn't fully idempotent as we end up accumulating runners especially during testing. However we also want to be able to run twice with different GitLab keys (e.g. project and personal) so I think we just have to be mindful of that during testing. Signed-off-by: Alex Bennée Acked-by: Richard Henderson Message-Id: <20230124180127.1881110-2-alex.bennee@linaro.org> --- scripts/ci/setup/gitlab-runner.yml | 60 ++++++++---------------------- scripts/ci/setup/vars.yml.template | 2 - 2 files changed, 15 insertions(+), 47 deletions(-) diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml index 33128be85d..95d4199c03 100644 --- a/scripts/ci/setup/gitlab-runner.yml +++ b/scripts/ci/setup/gitlab-runner.yml @@ -50,17 +50,25 @@ - name: Download the matching gitlab-runner get_url: - dest: /usr/local/bin/gitlab-runner - url: "https://s3.amazonaws.com/gitlab-runner-downloads/v{{ gitlab_runner_version }}/binaries/gitlab-runner-{{ gitlab_runner_os }}-{{ gitlab_runner_arch }}" - owner: gitlab-runner - group: gitlab-runner - mode: u=rwx,g=rwx,o=rx + dest: "/root/" + url: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_{{ gitlab_runner_arch }}.deb" + + - name: Install gitlab-runner via package manager + apt: deb="/root/gitlab-runner_{{ gitlab_runner_arch }}.deb" - name: Register the gitlab-runner - command: "/usr/local/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + + # The secondary runner will still run under the single gitlab-runner service + - name: Register secondary gitlab-runner + command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list aarch32,{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['architecture'] == 'aarch64' + - ansible_facts['distribution_version'] == '22.04' - name: Install the gitlab-runner service using its own functionality - command: /usr/local/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner + command: "/usr/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner" register: gitlab_runner_install_service_result failed_when: "gitlab_runner_install_service_result.rc != 0 and \"already exists\" not in gitlab_runner_install_service_result.stderr" @@ -69,41 +77,3 @@ name: gitlab-runner state: started enabled: yes - - - name: Download secondary gitlab-runner - get_url: - dest: /usr/local/bin/gitlab-runner-arm - url: "https://s3.amazonaws.com/gitlab-runner-downloads/v{{ gitlab_runner_version }}/binaries/gitlab-runner-{{ gitlab_runner_os }}-arm" - owner: gitlab-runner - group: gitlab-runner - mode: u=rwx,g=rwx,o=rx - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' - - - name: Register secondary gitlab-runner - command: "/usr/local/bin/gitlab-runner-arm register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list aarch32,{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' - - - name: Install the secondary gitlab-runner service using its own functionality - command: /usr/local/bin/gitlab-runner-arm install --user gitlab-runner --working-directory /home/gitlab-runner/arm -n gitlab-runner-arm - register: gitlab_runner_install_service_result - failed_when: "gitlab_runner_install_service_result.rc != 0 and \"already exists\" not in gitlab_runner_install_service_result.stderr" - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' - - - name: Enable the secondary gitlab-runner service - service: - name: gitlab-runner-arm - state: started - enabled: yes - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' diff --git a/scripts/ci/setup/vars.yml.template b/scripts/ci/setup/vars.yml.template index e48089761f..4b355fb80f 100644 --- a/scripts/ci/setup/vars.yml.template +++ b/scripts/ci/setup/vars.yml.template @@ -1,5 +1,3 @@ -# The version of the gitlab-runner to use -gitlab_runner_version: 13.12.0 # The URL of the gitlab server to use, usually https://gitlab.com unless you're # using a private GitLab instance gitlab_runner_server_url: https://gitlab.com From 075d909d044ef63a0b0cd1c04ad94d16f06ca923 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Tue, 24 Jan 2023 18:00:54 +0000 Subject: [PATCH 350/814] gitlab: add FF_SCRIPT_SECTIONS for timings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-Id: <20230124180127.1881110-3-alex.bennee@linaro.org> --- .gitlab-ci.d/base.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 69b36c148a..50fb59e147 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -6,6 +6,11 @@ # most restrictive to least restrictive # .base_job_template: + variables: + # Each script line from will be in a collapsible section in the job output + # and show the duration of each line. + FF_SCRIPT_SECTIONS: 1 + rules: ############################################################# # Stage 1: exclude scenarios where we definitely don't From c34bf19feb349360faa57147f9bbc16b1f27d6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:00:55 +0000 Subject: [PATCH 351/814] gitlab: just use plain --cc=clang for custom runner build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I think this was because older Ubuntu's didn't alias clang to whatever the latest version was. They do now so lets use that and not break. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-4-alex.bennee@linaro.org> --- .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml index abeb33eaff..725ca8ffea 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml @@ -81,7 +81,7 @@ ubuntu-22.04-aarch64-clang: script: - mkdir build - cd build - - ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers + - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check From c906e6fbaa50a3d9f9a5b24987e1a9d4ad70e9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:00:56 +0000 Subject: [PATCH 352/814] tests/unit: drop hacky race avoidance in test-io-channel-command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to play timing games to ensure one socat wins over the other, just create the fifo they both can use before spawning the processes. However in the process we need to disable two tests for Windows platforms as we don't have an abstraction for mkfifo(). Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1403 Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20230124180127.1881110-5-alex.bennee@linaro.org> --- tests/unit/test-io-channel-command.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/unit/test-io-channel-command.c b/tests/unit/test-io-channel-command.c index 19f72eab96..425e2f5594 100644 --- a/tests/unit/test-io-channel-command.c +++ b/tests/unit/test-io-channel-command.c @@ -20,6 +20,8 @@ #include "qemu/osdep.h" #include +#include +#include #include "io/channel-command.h" #include "io-channel-helpers.h" #include "qapi/error.h" @@ -29,6 +31,7 @@ static char *socat = NULL; +#ifndef _WIN32 static void test_io_channel_command_fifo(bool async) { g_autofree gchar *tmpdir = g_dir_make_tmp("qemu-test-io-channel.XXXXXX", NULL); @@ -40,12 +43,13 @@ static void test_io_channel_command_fifo(bool async) QIOChannel *src, *dst; QIOChannelTest *test; + if (mkfifo(fifo, 0600)) { + g_error("mkfifo: %s", strerror(errno)); + } + src = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) srcargv, O_WRONLY, &error_abort)); - /* try to avoid a race to create the socket */ - g_usleep(1000); - dst = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) dstargv, O_RDONLY, &error_abort)); @@ -60,7 +64,6 @@ static void test_io_channel_command_fifo(bool async) g_rmdir(tmpdir); } - static void test_io_channel_command_fifo_async(void) { if (!socat) { @@ -80,6 +83,7 @@ static void test_io_channel_command_fifo_sync(void) test_io_channel_command_fifo(false); } +#endif static void test_io_channel_command_echo(bool async) @@ -124,10 +128,12 @@ int main(int argc, char **argv) socat = g_find_program_in_path("socat"); +#ifndef _WIN32 g_test_add_func("/io/channel/command/fifo/sync", test_io_channel_command_fifo_sync); g_test_add_func("/io/channel/command/fifo/async", test_io_channel_command_fifo_async); +#endif g_test_add_func("/io/channel/command/echo/sync", test_io_channel_command_echo_sync); g_test_add_func("/io/channel/command/echo/async", From e2c4012bc35894d60e54bd077ceaaae565d43c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:00:57 +0000 Subject: [PATCH 353/814] build-sys: fix crlf-ending C code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On msys2, the shader-to-C script produces bad C: ./ui/shader/texture-blit-vert.h:2:5: error: missing terminating " character [-Werror] Fix it by changing the line ending from crlf to lf, and convert the script to Python (qemu build seems perl-free after that). Signed-off-by: Marc-André Lureau Acked-by: Thomas Huth Message-Id: <20230110132700.833690-2-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-6-alex.bennee@linaro.org> --- meson.build | 2 +- scripts/shaderinclude.pl | 16 ---------------- scripts/shaderinclude.py | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 17 deletions(-) delete mode 100644 scripts/shaderinclude.pl create mode 100644 scripts/shaderinclude.py diff --git a/meson.build b/meson.build index 6d3b665629..56320ae717 100644 --- a/meson.build +++ b/meson.build @@ -2779,7 +2779,7 @@ config_host_data.set('CONFIG_SLIRP', slirp.found()) genh += configure_file(output: 'config-host.h', configuration: config_host_data) hxtool = find_program('scripts/hxtool') -shaderinclude = find_program('scripts/shaderinclude.pl') +shaderinclude = find_program('scripts/shaderinclude.py') qapi_gen = find_program('scripts/qapi-gen.py') qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py', meson.current_source_dir() / 'scripts/qapi/commands.py', diff --git a/scripts/shaderinclude.pl b/scripts/shaderinclude.pl deleted file mode 100644 index cd3bb40b12..0000000000 --- a/scripts/shaderinclude.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -my $file = shift; -open FILE, "<", $file or die "open $file: $!"; -my $name = $file; -$name =~ s|.*/||; -$name =~ s/[-.]/_/g; -print "static GLchar ${name}_src[] =\n"; -while () { - chomp; - printf " \"%s\\n\"\n", $_; -} -print " \"\\n\";\n"; -close FILE; diff --git a/scripts/shaderinclude.py b/scripts/shaderinclude.py new file mode 100644 index 0000000000..ab2aade2cd --- /dev/null +++ b/scripts/shaderinclude.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 Red Hat, Inc. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import sys +import os + + +def main(args): + file_path = args[1] + basename = os.path.basename(file_path) + varname = basename.replace('-', '_').replace('.', '_') + + with os.fdopen(sys.stdout.fileno(), "wt", closefd=False, newline='\n') as stdout: + with open(file_path, "r", encoding='utf-8') as file: + print(f'static GLchar {varname}_src[] =', file=stdout) + for line in file: + line = line.rstrip() + print(f' "{line}\\n"', file=stdout) + print(' "\\n";', file=stdout) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) From 7195f30248c4e55ebd56cbe370547571fdf5c144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:00:58 +0000 Subject: [PATCH 354/814] .gitlab-ci.d/windows: do not disable opengl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous patch should have fixed shader compilation. Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230110132700.833690-3-marcandre.lureau@redhat.com> [AJB: tweak commit message] Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-7-alex.bennee@linaro.org> --- .gitlab-ci.d/windows.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index a1d5790580..cf445b77f6 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -71,7 +71,7 @@ msys2-64bit: # for the msys2 64-bit job, due to the build could not complete within # the project timeout. - ..\msys64\usr\bin\bash -lc '../configure --target-list=x86_64-softmmu - --without-default-devices --disable-opengl' + --without-default-devices' - ..\msys64\usr\bin\bash -lc 'make' # qTests don't run successfully with "--without-default-devices", # so let's exclude the qtests from CI for now. @@ -113,8 +113,7 @@ msys2-32bit: - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - mkdir output - cd output - - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu - --disable-opengl' + - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu' - ..\msys64\usr\bin\bash -lc 'make' - ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" || { cat meson-logs/testlog.txt; exit 1; }' From ec91e923784df086bdb3bd39569203524aa75875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:00:59 +0000 Subject: [PATCH 355/814] meson: replace Perl usage with Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's try to remove Perl usage during build time. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230110132700.833690-5-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-8-alex.bennee@linaro.org> --- tests/qapi-schema/meson.build | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 9dfe98bc9a..d85b14f28c 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -259,22 +259,23 @@ if build_docs # Fix possible inconsistency in line endings in generated output and # in the golden reference (which could otherwise cause test failures # on Windows hosts). Unfortunately diff --strip-trailing-cr - # is GNU-diff only. The odd-looking perl is because we must avoid + # is GNU-diff only. The odd-looking python is because we must avoid # using an explicit '\' character in the command arguments to # a custom_target(), as Meson will unhelpfully replace it with a '/' # (https://github.com/mesonbuild/meson/issues/1564) + remove_cr = [python, '-c', 'import sys;[sys.stdout.write(line.replace(chr(13), "")) for line in sys.stdin]'] qapi_doc_out_nocr = custom_target('QAPI rST doc newline-sanitized', output: ['doc-good.txt.nocr'], input: qapi_doc_out[0], build_by_default: true, - command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'], + command: [remove_cr, '@INPUT@'], capture: true) qapi_doc_ref_nocr = custom_target('QAPI rST doc reference newline-sanitized', output: ['doc-good.ref.nocr'], input: files('doc-good.txt'), build_by_default: true, - command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'], + command: [remove_cr, '@INPUT@'], capture: true) test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0], qapi_doc_out_nocr[0]], From d89935c95e5ba7e2685da71e4756fa63fde764af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:01:00 +0000 Subject: [PATCH 356/814] docs: drop texinfo options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like this is no longer wanted, we only build the html output. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé Message-Id: <20230110132700.833690-6-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-9-alex.bennee@linaro.org> --- docs/conf.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e33cf3d381..73a287a4f2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -297,19 +297,6 @@ man_pages = [ ] man_make_section_directory = False -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'QEMU', u'QEMU Documentation', - author, 'QEMU', 'One line description of project.', - 'Miscellaneous'), -] - - - # We use paths starting from qemu_docdir here so that you can run # sphinx-build from anywhere and the kerneldoc extension can still # find everything. From 3ab8bf8341ae42efbefbb99bff6d703c302b1d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:01 +0000 Subject: [PATCH 357/814] gitlab: add lsan suppression file to workaround tcmalloc issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The up-coming upgrade to Fedora 37 will bring in libtcmalloc as a dependency of libglusterfs which confuses our fuzz run. Rather than disable the build lets use LSAN's suppression mechanism to prevent the job from failing. Signed-off-by: Alex Bennée Cc: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20230124180127.1881110-10-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest.yml | 1 + scripts/oss-fuzz/lsan_suppressions.txt | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 scripts/oss-fuzz/lsan_suppressions.txt diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index f09a898c3e..9a6ba1fe3b 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -511,6 +511,7 @@ build-oss-fuzz: IMAGE: fedora script: - mkdir build-oss-fuzz + - export LSAN_OPTIONS=suppressions=scripts/oss-fuzz/lsan_suppressions.txt - CC="clang" CXX="clang++" CFLAGS="-fsanitize=address" ./scripts/oss-fuzz/build.sh - export ASAN_OPTIONS="fast_unwind_on_malloc=0" diff --git a/scripts/oss-fuzz/lsan_suppressions.txt b/scripts/oss-fuzz/lsan_suppressions.txt new file mode 100644 index 0000000000..02ec0a6ed5 --- /dev/null +++ b/scripts/oss-fuzz/lsan_suppressions.txt @@ -0,0 +1,2 @@ +# The tcmalloc on Fedora37 confuses things +leak:/lib64/libtcmalloc_minimal.so.4 From 0054dc8bde408d61257bacdb489bbacc4ca5cde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:01:02 +0000 Subject: [PATCH 358/814] Update lcitool and fedora to 37 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fedora 35 is EOL. Update to upstream lcitool, that dropped f35 and added f37. Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230110132700.833690-7-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-11-alex.bennee@linaro.org> --- tests/docker/dockerfiles/fedora-win32-cross.docker | 4 ++-- tests/docker/dockerfiles/fedora-win64-cross.docker | 4 ++-- tests/docker/dockerfiles/fedora.docker | 4 ++-- tests/lcitool/libvirt-ci | 2 +- tests/lcitool/refresh | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 75383ba185..cc5d1ac4be 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw32 fedora-35 qemu +# $ lcitool dockerfile --layers all --cross mingw32 fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index 98c03dc13b..cabbf4edfc 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw64 fedora-35 qemu +# $ lcitool dockerfile --layers all --cross mingw64 fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index d200c7fc10..f44b005000 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all fedora-35 qemu +# $ lcitool dockerfile --layers all fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index e3eb28cf2e..319a534c22 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit e3eb28cf2e17fbcf7fe7e19505ee432b8ec5bbb5 +Subproject commit 319a534c220f53fc8670254cac25d6f662c82112 diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index fa966e4009..a5ea0efc3b 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -111,7 +111,7 @@ try: generate_dockerfile("centos8", "centos-stream-8") generate_dockerfile("debian-amd64", "debian-11", trailer="".join(debian11_extras)) - generate_dockerfile("fedora", "fedora-35") + generate_dockerfile("fedora", "fedora-37") generate_dockerfile("opensuse-leap", "opensuse-leap-153") generate_dockerfile("ubuntu2004", "ubuntu-2004", trailer="".join(ubuntu2004_tsanhack)) @@ -161,12 +161,12 @@ try: trailer=cross_build("s390x-linux-gnu-", "s390x-softmmu,s390x-linux-user")) - generate_dockerfile("fedora-win32-cross", "fedora-35", + generate_dockerfile("fedora-win32-cross", "fedora-37", cross="mingw32", trailer=cross_build("i686-w64-mingw32-", "i386-softmmu")) - generate_dockerfile("fedora-win64-cross", "fedora-35", + generate_dockerfile("fedora-win64-cross", "fedora-37", cross="mingw64", trailer=cross_build("x86_64-w64-mingw32-", "x86_64-softmmu")) From 7a6e869cb5eebc45d6820457e9e65f53132407d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:01:03 +0000 Subject: [PATCH 359/814] lcitool: drop perl from QEMU project/dependencies 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é Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230110132700.833690-8-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-12-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus/freebsd-12.vars | 2 +- .gitlab-ci.d/cirrus/freebsd-13.vars | 2 +- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- scripts/ci/setup/build-environment.yml | 1 - tests/docker/dockerfiles/alpine.docker | 1 - tests/docker/dockerfiles/centos8.docker | 1 - tests/docker/dockerfiles/debian-amd64-cross.docker | 1 - tests/docker/dockerfiles/debian-amd64.docker | 1 - tests/docker/dockerfiles/debian-arm64-cross.docker | 1 - tests/docker/dockerfiles/debian-armel-cross.docker | 1 - tests/docker/dockerfiles/debian-armhf-cross.docker | 1 - tests/docker/dockerfiles/debian-mips64el-cross.docker | 1 - tests/docker/dockerfiles/debian-mipsel-cross.docker | 1 - tests/docker/dockerfiles/debian-ppc64el-cross.docker | 1 - tests/docker/dockerfiles/debian-s390x-cross.docker | 1 - tests/docker/dockerfiles/debian-tricore-cross.docker | 1 - tests/docker/dockerfiles/fedora-win32-cross.docker | 1 - tests/docker/dockerfiles/fedora-win64-cross.docker | 1 - tests/docker/dockerfiles/fedora.docker | 1 - tests/docker/dockerfiles/opensuse-leap.docker | 1 - tests/docker/dockerfiles/ubuntu2004.docker | 1 - tests/lcitool/projects/qemu.yml | 1 - tests/vm/centos.aarch64 | 2 +- 23 files changed, 4 insertions(+), 23 deletions(-) diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars index e3fc3235b9..f32f01a954 100644 --- a/.gitlab-ci.d/cirrus/freebsd-12.vars +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars index 9f56babd9c..813c051616 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index ef9e14b373..33bb4e1040 100644 --- a/.gitlab-ci.d/cirrus/macos-12.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake' NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' -PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' +PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' PYTHON='/opt/homebrew/bin/python3' diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index b04c2b7cee..58438008ee 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -155,7 +155,6 @@ - nettle-devel - ninja-build - nmap-ncat - - perl-Test-Harness - pixman-devel - python36 - rdma-core-devel diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 094f66f4eb..3293c790c9 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -77,7 +77,6 @@ RUN apk update && \ numactl-dev \ openssh-client \ pcre-dev \ - perl \ pixman-dev \ pkgconf \ pulseaudio-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 1f70d41aeb..f13745e6cc 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -91,7 +91,6 @@ RUN dnf distro-sync -y && \ openssh-clients \ pam-devel \ pcre-static \ - perl \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 5e57309361..d0ace6d0f7 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index bfeab01ee3..0517c4c315 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ nettle-dev \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 98885bd0ee..9ac1c1ba3f 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index d5c08714e4..8be492f4ad 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 471444fcf4..da789e04af 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 15b0224b76..8b7c59c4f9 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index a5d3ca6e2f..f9f1ed5fd2 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index d2954e61f6..e423d88c2d 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index d43ce16317..c1134f4cec 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index b573b9ded2..34b2cea4e3 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -28,7 +28,6 @@ RUN apt update && \ locales \ make \ ninja-build \ - perl-base \ pkgconf \ python3-pip \ python3-setuptools \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index cc5d1ac4be..de811b332b 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -42,7 +42,6 @@ exec "$@"' > /usr/bin/nosync && \ nmap-ncat \ openssh-clients \ pcre-static \ - perl-base \ python3 \ python3-PyYAML \ python3-numpy \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index cabbf4edfc..71681d6f92 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -42,7 +42,6 @@ exec "$@"' > /usr/bin/nosync && \ nmap-ncat \ openssh-clients \ pcre-static \ - perl-base \ python3 \ python3-PyYAML \ python3-numpy \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index f44b005000..ca3793b04b 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -98,7 +98,6 @@ exec "$@"' > /usr/bin/nosync && \ openssh-clients \ pam-devel \ pcre-static \ - perl-base \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 4361b01464..680f49e7dc 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -88,7 +88,6 @@ RUN zypper update -y && \ openssh \ pam-devel \ pcre-devel-static \ - perl-base \ pkgconfig \ python3-Pillow \ python3-PyYAML \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 9417bca2fa..6594bba338 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -105,7 +105,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ nettle-dev \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index c62dbc00f9..c2af92348a 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -83,7 +83,6 @@ packages: - ncursesw - pam - pcre-static - - perl - pixman - pkg-config - pulseaudio diff --git a/tests/vm/centos.aarch64 b/tests/vm/centos.aarch64 index 2de7ef6992..3f58de1e64 100755 --- a/tests/vm/centos.aarch64 +++ b/tests/vm/centos.aarch64 @@ -28,7 +28,7 @@ DEFAULT_CONFIG = { "dnf config-manager --set-enabled powertools, " "dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo, " "dnf install -y make ninja-build git python38 gcc gcc-c++ flex bison "\ - "glib2-devel perl pixman-devel zlib-devel docker-ce.aarch64, " + "glib2-devel pixman-devel zlib-devel docker-ce.aarch64, " "systemctl enable docker, " ), # We increase beyond the default time since during boot From df07c72a74fd43bfc1e6431a19eb3252a3cfe1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 24 Jan 2023 18:01:04 +0000 Subject: [PATCH 360/814] lcitool: drop texinfo from QEMU project/dependencies 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é Message-Id: <20230110132700.833690-9-marcandre.lureau@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-13-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus/freebsd-12.vars | 2 +- .gitlab-ci.d/cirrus/freebsd-13.vars | 2 +- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- tests/docker/dockerfiles/alpine.docker | 1 - tests/docker/dockerfiles/centos8.docker | 1 - tests/docker/dockerfiles/debian-amd64-cross.docker | 3 +-- tests/docker/dockerfiles/debian-amd64.docker | 1 - tests/docker/dockerfiles/debian-arm64-cross.docker | 3 +-- tests/docker/dockerfiles/debian-armel-cross.docker | 3 +-- tests/docker/dockerfiles/debian-armhf-cross.docker | 3 +-- tests/docker/dockerfiles/debian-mips64el-cross.docker | 3 +-- tests/docker/dockerfiles/debian-mipsel-cross.docker | 3 +-- tests/docker/dockerfiles/debian-ppc64el-cross.docker | 3 +-- tests/docker/dockerfiles/debian-s390x-cross.docker | 3 +-- tests/docker/dockerfiles/debian-toolchain.docker | 1 - tests/docker/dockerfiles/fedora-win32-cross.docker | 1 - tests/docker/dockerfiles/fedora-win64-cross.docker | 1 - tests/docker/dockerfiles/fedora.docker | 1 - tests/docker/dockerfiles/opensuse-leap.docker | 1 - tests/docker/dockerfiles/ubuntu2004.docker | 1 - tests/lcitool/projects/qemu.yml | 1 - 21 files changed, 11 insertions(+), 29 deletions(-) diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars index f32f01a954..8934e5d57f 100644 --- a/.gitlab-ci.d/cirrus/freebsd-12.vars +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars index 813c051616..65ce456c48 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index 33bb4e1040..65b78fa08f 100644 --- a/.gitlab-ci.d/cirrus/macos-12.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake' NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' -PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd' +PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract usbredir vde vte3 zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' PYTHON='/opt/homebrew/bin/python3' diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 3293c790c9..4a569d82f6 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -99,7 +99,6 @@ RUN apk update && \ spice-protocol \ tar \ tesseract-ocr \ - texinfo \ usbredir-dev \ util-linux \ vde2-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index f13745e6cc..fbc953c6dc 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -110,7 +110,6 @@ RUN dnf distro-sync -y && \ systemd-devel \ systemtap-sdt-devel \ tar \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index d0ace6d0f7..5175095a85 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 0517c4c315..b61f664ea2 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -125,7 +125,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ tar \ tesseract-ocr \ tesseract-ocr-eng \ - texinfo \ xfslibs-dev \ zlib1g-dev && \ eatmydata apt-get autoremove -y && \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 9ac1c1ba3f..b69958c69f 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index 8be492f4ad..96b524fab6 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index da789e04af..08a75cebdb 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 8b7c59c4f9..5930e6fa5d 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index f9f1ed5fd2..c65d9830e7 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index e423d88c2d..2ae56c978e 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index c1134f4cec..0db86a0fcd 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -55,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-toolchain.docker b/tests/docker/dockerfiles/debian-toolchain.docker index d3d4d3344e..6c73408b34 100644 --- a/tests/docker/dockerfiles/debian-toolchain.docker +++ b/tests/docker/dockerfiles/debian-toolchain.docker @@ -21,7 +21,6 @@ RUN apt update && \ libmpc-dev \ libmpfr-dev \ rsync \ - texinfo \ wget && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt build-dep -yy --arch-only gcc glibc diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index de811b332b..b659c0b8a8 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -57,7 +57,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ util-linux \ which && \ nosync dnf autoremove -y && \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index 71681d6f92..0a404c15bf 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -57,7 +57,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ util-linux \ which && \ nosync dnf autoremove -y && \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index ca3793b04b..5d60a96141 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -121,7 +121,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 680f49e7dc..4b2c02d6ab 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -111,7 +111,6 @@ RUN zypper update -y && \ tar \ tesseract-ocr \ tesseract-ocr-traineddata-english \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 6594bba338..13ab0b6887 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -124,7 +124,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ tar \ tesseract-ocr \ tesseract-ocr-eng \ - texinfo \ xfslibs-dev \ zlib1g-dev && \ eatmydata apt-get autoremove -y && \ diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index c2af92348a..6467bcf08a 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -109,7 +109,6 @@ packages: - tar - tesseract - tesseract-eng - - texinfo - usbredir - virglrenderer - vte From 7ac17cb8b2ab012e6289b4d77fd220a96511d88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 24 Jan 2023 18:01:05 +0000 Subject: [PATCH 361/814] tests/docker: Install flex in debian-tricore-cross MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When flex is not available, binutils sources default to the 'missing' script, but the current script available is not in the format expected by the 'configure' script: $ ./configure ... /usr/src/binutils/missing: Unknown `--run' option Try `/usr/src/binutils/missing --help' for more information configure: WARNING: `missing' script is too old or missing ... checking for bison... bison -y checking for flex... no checking for lex... no checking for flex... /usr/src/binutils/missing flex $ make ... updating ldgram.h gcc -DHAVE_CONFIG_H -I. -I. -I. -D_GNU_SOURCE -I. -I. -I../bfd -I./../bfd -I./../include -I./../intl -I../intl -w -DLOCALEDIR="\"/usr/local/share/locale\"" -W -Wall -Wstrict-prototypes -Wmissing-prototypes -w -c `test -f 'ldgram.c' || echo './'`ldgram.c `test -f ldlex.l || echo './'`ldlex.l /bin/sh: 1: ldlex.l: not found make[3]: *** [Makefile:662: ldlex.c] Error 127 make[3]: Leaving directory '/usr/src/binutils/ld' make[2]: *** [Makefile:799: all-recursive] Error 1 By pass the 'missing' script use by directly installing 'flex' in the container. Reported-by: Peter Maydell Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230112155643.7408-1-philmd@linaro.org> Reviewed-by: Bastian-Koppelmann Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-14-alex.bennee@linaro.org> --- tests/docker/dockerfiles/debian-tricore-cross.docker | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 34b2cea4e3..5ae58efa09 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -20,6 +20,7 @@ RUN apt update && \ bzip2 \ ca-certificates \ ccache \ + flex \ g++ \ gcc \ git \ From 5b9636326248a736b1d14b6132a9ae41d5f92fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:06 +0000 Subject: [PATCH 362/814] tests/docker: drop debian-tricore-cross's partial status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This image is perfectly capable of building QEMU, and indeed we do that on gitlab. Drop the DOCKER_PARTIAL_IMAGES setting so we can also test the gitlab build locally. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-15-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 665ddde518..bfb0dcac21 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -128,7 +128,6 @@ DOCKER_PARTIAL_IMAGES += debian-mips-cross DOCKER_PARTIAL_IMAGES += debian-nios2-cross DOCKER_PARTIAL_IMAGES += debian-riscv64-test-cross DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross -DOCKER_PARTIAL_IMAGES += debian-tricore-cross DOCKER_PARTIAL_IMAGES += debian-xtensa-cross DOCKER_PARTIAL_IMAGES += fedora-cris-cross From 5842de51573fdbd7299ab4b33d64b7446cc07649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:07 +0000 Subject: [PATCH 363/814] tests/tcg: skip the vma-pthread test on CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are getting a lot of failures that are not related to changes so this could be a flaky test. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-16-alex.bennee@linaro.org> --- tests/tcg/multiarch/Makefile.target | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index e7213af492..ae8b3d7268 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -42,6 +42,15 @@ munmap-pthread: LDFLAGS+=-pthread vma-pthread: CFLAGS+=-pthread vma-pthread: LDFLAGS+=-pthread +# The vma-pthread seems very sensitive on gitlab and we currently +# don't know if its exposing a real bug or the test is flaky. +ifneq ($(GITLAB_CI),) +run-vma-pthread: vma-pthread + $(call skip-test, $<, "flaky on CI?") +run-plugin-vma-pthread-with-%: vma-pthread + $(call skip-test, $<, "flaky on CI?") +endif + # We define the runner for test-mmap after the individual # architectures have defined their supported pages sizes. If no # additional page sizes are defined we only run the default test. From 57dbce5a4f76c2e2201905a6211eb2a83a8bacce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 24 Jan 2023 18:01:08 +0000 Subject: [PATCH 364/814] tests/tcg: Use SIGKILL for timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux-user blocks all signals while attempting to handle guest signals (e.g. ABRT), which means that the default TERM sent by timeout has no effect -- KILL instead. Signed-off-by: Richard Henderson Message-Id: <20230117035701.168514-2-richard.henderson@linaro.org> [AJB: expanded commit message from cover letter] Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230124180127.1881110-17-alex.bennee@linaro.org> --- tests/tcg/Makefile.target | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 14bc013181..a3b0aaf8af 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -54,10 +54,10 @@ cc-option = if $(call cc-test, $1); then \ # $1 = test name, $2 = cmd, $3 = desc ifeq ($(filter %-softmmu, $(TARGET)),) -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \ +run-test = $(call quiet-command, timeout -s KILL --foreground $(TIMEOUT) $2 > $1.out, \ TEST,$(or $3, $*, $<) on $(TARGET_NAME)) else -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2, \ +run-test = $(call quiet-command, timeout -s KILL --foreground $(TIMEOUT) $2, \ TEST,$(or $3, $*, $<) on $(TARGET_NAME)) endif From 6e890b0521674c74c4a34b847fa8d7c57e43aadf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:09 +0000 Subject: [PATCH 365/814] gitlab: wrap up test results for custom runners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of spewing the whole log to stdout lets just define them as build artefacts so we can examine them later. Where we are running check-tcg run it first as those tests are yet to be integrated into meson. To avoid confusion we don't run multiple check-tcg tests at once. Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-18-alex.bennee@linaro.org> --- .gitlab-ci.d/custom-runners.yml | 11 +++++++++++ .gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml | 13 ++++++------- .../custom-runners/ubuntu-22.04-aarch32.yml | 2 +- .../custom-runners/ubuntu-22.04-aarch64.yml | 13 ++++++------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 97f99e29c2..9fdc476c48 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -13,6 +13,17 @@ variables: GIT_STRATEGY: clone +# All custom runners can extend this template to upload the testlog +# data as an artifact and also feed the junit report +.custom_artifacts_template: + artifacts: + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + expire_in: 7 days + paths: + - build/meson-logs/testlog.txt + reports: + junit: build/meson-logs/testlog.junit.xml + include: - local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml' - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml' diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml index fcaef9e5ef..f512eaeaa3 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04/20.04" ubuntu-20.04-s390x-all-linux-static: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -19,12 +20,11 @@ ubuntu-20.04-s390x-all-linux-static: - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` + - make --output-sync check-tcg - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; - - make --output-sync -j`nproc` check-tcg - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -41,9 +41,9 @@ ubuntu-20.04-s390x-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-alldbg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -64,9 +64,9 @@ ubuntu-20.04-s390x-alldbg: - make clean - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-clang: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -86,7 +86,6 @@ ubuntu-20.04-s390x-clang: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-tci: needs: [] @@ -109,6 +108,7 @@ ubuntu-20.04-s390x-tci: - make --output-sync -j`nproc` ubuntu-20.04-s390x-notcg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -128,4 +128,3 @@ ubuntu-20.04-s390x-notcg: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml index 2c386fa3e9..42137aaf2a 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-22.04-aarch32-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -22,4 +23,3 @@ ubuntu-22.04-aarch32-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml index 725ca8ffea..8ba85be440 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-22.04-aarch64-all-linux-static: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -19,12 +20,11 @@ ubuntu-22.04-aarch64-all-linux-static: - ../configure --enable-debug --static --disable-system --disable-pie || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` + - make check-tcg - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; - - make --output-sync -j`nproc --ignore=40` check-tcg - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -44,9 +44,9 @@ ubuntu-22.04-aarch64-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-alldbg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -63,9 +63,9 @@ ubuntu-22.04-aarch64-alldbg: - make clean - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-clang: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -85,7 +85,6 @@ ubuntu-22.04-aarch64-clang: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-tci: needs: [] @@ -108,6 +107,7 @@ ubuntu-22.04-aarch64-tci: - make --output-sync -j`nproc --ignore=40` ubuntu-22.04-aarch64-notcg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -127,4 +127,3 @@ ubuntu-22.04-aarch64-notcg: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; From 51d11acf3163b2f09e3e3d1ab7c102c82cacc40c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 24 Jan 2023 18:01:10 +0000 Subject: [PATCH 366/814] MAINTAINERS: Fix the entry for tests/tcg/nios2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/tcg/nios2/Makefile.target has accidentally been added to the Microblaze section. Move it into the correct nios2 section instead - and while we're at it, it should also cover the whole folder, and not only the Makefile. Fixes: 67f80eb4d0 ("tests/tcg: enable debian-nios2-cross for test building") Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230119130326.2030297-1-thuth@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-19-alex.bennee@linaro.org> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c581c11a64..629ab5bbb1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -240,7 +240,6 @@ F: target/microblaze/ F: hw/microblaze/ F: disas/microblaze.c F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh -F: tests/tcg/nios2/Makefile.target MIPS TCG CPUs M: Philippe Mathieu-Daudé @@ -262,6 +261,7 @@ F: hw/nios2/ F: disas/nios2.c F: configs/devices/nios2-softmmu/default.mak F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh +F: tests/tcg/nios2/ OpenRISC TCG CPUs M: Stafford Horne From 9d195efd6588100f8074a1c8daf9f403ebf39740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:11 +0000 Subject: [PATCH 367/814] docs: add hotlinks to about preface text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it easier to navigate the documentation. Reviewed-by: Peter Maydell Acked-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230124180127.1881110-20-alex.bennee@linaro.org> --- docs/about/index.rst | 16 ++++++++-------- docs/system/index.rst | 2 ++ docs/tools/index.rst | 2 ++ docs/user/index.rst | 2 ++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/about/index.rst b/docs/about/index.rst index 5bea653c07..bae1309cc6 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -5,19 +5,19 @@ About QEMU QEMU is a generic and open source machine emulator and virtualizer. QEMU can be used in several different ways. The most common is for -"system emulation", where it provides a virtual model of an +:ref:`System Emulation`, where it provides a virtual model of an entire machine (CPU, memory and emulated devices) to run a guest OS. -In this mode the CPU may be fully emulated, or it may work with -a hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to -allow the guest to run directly on the host CPU. +In this mode the CPU may be fully emulated, or it may work with a +hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to allow the +guest to run directly on the host CPU. -The second supported way to use QEMU is "user mode emulation", +The second supported way to use QEMU is :ref:`User Mode Emulation`, where QEMU can launch processes compiled for one CPU on another CPU. In this mode the CPU is always emulated. -QEMU also provides a number of standalone commandline utilities, -such as the ``qemu-img`` disk image utility that allows you to create, -convert and modify disk images. +QEMU also provides a number of standalone :ref:`command line +utilities`, such as the ``qemu-img`` disk image utility that +allows you to create, convert and modify disk images. .. toctree:: :maxdepth: 2 diff --git a/docs/system/index.rst b/docs/system/index.rst index e3695649c5..282b6ffb56 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -1,3 +1,5 @@ +.. _System Emulation: + ---------------- System Emulation ---------------- diff --git a/docs/tools/index.rst b/docs/tools/index.rst index 1edd5a8054..2151adcf78 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -1,3 +1,5 @@ +.. _Tools: + ----- Tools ----- diff --git a/docs/user/index.rst b/docs/user/index.rst index 2c4e29f3db..782d27cda2 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -1,3 +1,5 @@ +.. _User Mode Emulation: + ------------------- User Mode Emulation ------------------- From a0a6754bb549b255a269b9ab63674e06a1d14ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:12 +0000 Subject: [PATCH 368/814] docs: add a new section to outline emulation support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This affects both system and user mode emulation so we should probably list it up front. Acked-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-21-alex.bennee@linaro.org> --- docs/about/emulation.rst | 103 ++++++++++++++++++++++++++++++++++ docs/about/index.rst | 1 + docs/devel/tcg-plugins.rst | 2 + docs/system/arm/emulation.rst | 2 + 4 files changed, 108 insertions(+) create mode 100644 docs/about/emulation.rst diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst new file mode 100644 index 0000000000..7ec7e09381 --- /dev/null +++ b/docs/about/emulation.rst @@ -0,0 +1,103 @@ +Emulation +========= + +QEMU's Tiny Code Generator (TCG) provides the ability to emulate a +number of CPU architectures on any supported host platform. Both +:ref:`System Emulation` and :ref:`User Mode Emulation` are supported +depending on the guest architecture. + +.. list-table:: Supported Guest Architectures for Emulation + :widths: 30 10 10 50 + :header-rows: 1 + + * - Architecture (qemu name) + - System + - User + - Notes + * - Alpha + - Yes + - Yes + - Legacy 64 bit RISC ISA developed by DEC + * - Arm (arm, aarch64) + - :ref:`Yes` + - Yes + - Wide range of features, see :ref:`Arm Emulation` for details + * - AVR + - :ref:`Yes` + - No + - 8 bit micro controller, often used in maker projects + * - Cris + - Yes + - Yes + - Embedded RISC chip developed by AXIS + * - Hexagon + - No + - Yes + - Family of DSPs by Qualcomm + * - PA-RISC (hppa) + - Yes + - Yes + - A legacy RISC system used in HP's old minicomputers + * - x86 (i386, x86_64) + - :ref:`Yes` + - Yes + - The ubiquitous desktop PC CPU architecture, 32 and 64 bit. + * - Loongarch + - Yes + - Yes + - A MIPS-like 64bit RISC architecture developed in China + * - m68k + - :ref:`Yes` + - Yes + - Motorola 68000 variants and ColdFire + * - Microblaze + - Yes + - Yes + - RISC based soft-core by Xilinx + * - MIPS (mips*) + - :ref:`Yes` + - Yes + - Venerable RISC architecture originally out of Stanford University + * - Nios2 + - Yes + - Yes + - 32 bit embedded soft-core by Altera + * - OpenRISC + - :ref:`Yes` + - Yes + - Open source RISC architecture developed by the OpenRISC community + * - Power (ppc, ppc64) + - :ref:`Yes` + - Yes + - A general purpose RISC architecture now managed by IBM + * - RISC-V + - :ref:`Yes` + - Yes + - An open standard RISC ISA maintained by RISC-V International + * - RX + - :ref:`Yes` + - No + - A 32 bit micro controller developed by Renesas + * - s390x + - :ref:`Yes` + - Yes + - A 64 bit CPU found in IBM's System Z mainframes + * - sh4 + - Yes + - Yes + - A 32 bit RISC embedded CPU developed by Hitachi + * - SPARC (sparc, sparc64) + - :ref:`Yes` + - Yes + - A RISC ISA originally developed by Sun Microsystems + * - Tricore + - Yes + - No + - A 32 bit RISC/uController/DSP developed by Infineon + * - Xtensa + - :ref:`Yes` + - Yes + - A configurable 32 bit soft core now owned by Cadence + +A number of features are are only available when running under +emulation including :ref:`Record/Replay` and :ref:`TCG Plugins`. diff --git a/docs/about/index.rst b/docs/about/index.rst index bae1309cc6..b00b584b31 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -23,6 +23,7 @@ allows you to create, convert and modify disk images. :maxdepth: 2 build-platforms + emulation deprecated removed-features license diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 9740a70406..81dcd43a61 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -3,6 +3,8 @@ Copyright (c) 2019, Linaro Limited Written by Emilio Cota and Alex Bennée +.. _TCG Plugins: + QEMU TCG Plugins ================ diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index b33d7c28dc..b87e064d9d 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -1,3 +1,5 @@ +.. _Arm Emulation: + A-profile CPU architecture support ================================== From 2da9d21360cdabde1bb0dad7ae06e7df5dcb7835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:13 +0000 Subject: [PATCH 369/814] semihosting: add semihosting section to the docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main reason to do this is to document our O_BINARY implementation decision somewhere. However I've also moved some of the implementation details out of qemu-options and added links between the two. As a bonus I've highlighted the scary warnings about host access with the appropriate RST tags. Acked-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-22-alex.bennee@linaro.org> --- docs/about/emulation.rst | 87 ++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 25 ++++-------- 2 files changed, 95 insertions(+), 17 deletions(-) diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst index 7ec7e09381..b510a54418 100644 --- a/docs/about/emulation.rst +++ b/docs/about/emulation.rst @@ -101,3 +101,90 @@ depending on the guest architecture. A number of features are are only available when running under emulation including :ref:`Record/Replay` and :ref:`TCG Plugins`. + +.. _Semihosting: + +Semihosting +----------- + +Semihosting is a feature defined by the owner of the architecture to +allow programs to interact with a debugging host system. On real +hardware this is usually provided by an In-circuit emulator (ICE) +hooked directly to the board. QEMU's implementation allows for +semihosting calls to be passed to the host system or via the +``gdbstub``. + +Generally semihosting makes it easier to bring up low level code before a +more fully functional operating system has been enabled. On QEMU it +also allows for embedded micro-controller code which typically doesn't +have a full libc to be run as "bare-metal" code under QEMU's user-mode +emulation. It is also useful for writing test cases and indeed a +number of compiler suites as well as QEMU itself use semihosting calls +to exit test code while reporting the success state. + +Semihosting is only available using TCG emulation. This is because the +instructions to trigger a semihosting call are typically reserved +causing most hypervisors to trap and fault on them. + +.. warning:: + Semihosting inherently bypasses any isolation there may be between + the guest and the host. As a result a program using semihosting can + happily trash your host system. You should only ever run trusted + code with semihosting enabled. + +Redirection +~~~~~~~~~~~ + +Semihosting calls can be re-directed to a (potentially remote) gdb +during debugging via the :ref:`gdbstub`. Output to the +semihosting console is configured as a ``chardev`` so can be +redirected to a file, pipe or socket like any other ``chardev`` +device. + +Supported Targets +~~~~~~~~~~~~~~~~~ + +Most targets offer similar semihosting implementations with some +minor changes to define the appropriate instruction to encode the +semihosting call and which registers hold the parameters. They tend to +presents a simple POSIX-like API which allows your program to read and +write files, access the console and some other basic interactions. + +For full details of the ABI for a particular target, and the set of +calls it provides, you should consult the semihosting specification +for that architecture. + +.. note:: + QEMU makes an implementation decision to implement all file + access in ``O_BINARY`` mode. The user-visible effect of this is + regardless of the text/binary mode the program sets QEMU will + always select a binary mode ensuring no line-terminator conversion + is performed on input or output. This is because gdb semihosting + support doesn't make the distinction between the modes and + magically processing line endings can be confusing. + +.. list-table:: Guest Architectures supporting Semihosting + :widths: 10 10 80 + :header-rows: 1 + + * - Architecture + - Modes + - Specification + * - Arm + - System and User-mode + - https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst + * - m68k + - System + - https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=libgloss/m68k/m68k-semi.txt;hb=HEAD + * - MIPS + - System + - Unified Hosting Interface (MD01069) + * - Nios II + - System + - https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD + * - RISC-V + - System and User-mode + - https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc + * - Xtensa + - System + - Tensilica ISS SIMCALL diff --git a/qemu-options.hx b/qemu-options.hx index d59d19704b..88e93c6103 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4633,10 +4633,11 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting, QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting`` - Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). + Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). - Note that this allows guest direct access to the host filesystem, so - should only be used with a trusted guest OS. + .. warning:: + Note that this allows guest direct access to the host filesystem, so + should only be used with a trusted guest OS. See the -semihosting-config option documentation for further information about the facilities this enables. @@ -4648,22 +4649,12 @@ QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]`` - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V + Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). - Note that this allows guest direct access to the host filesystem, so - should only be used with a trusted guest OS. - - On Arm this implements the standard semihosting API, version 2.0. - - On M68K this implements the "ColdFire GDB" interface used by - libgloss. - - Xtensa semihosting provides basic file IO calls, such as - open/read/write/seek/select. Tensilica baremetal libc for ISS and - linux platform "sim" use this interface. - - On RISC-V this implements the standard semihosting API, version 0.2. + .. warning:: + Note that this allows guest direct access to the host filesystem, so + should only be used with a trusted guest OS. ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU From 2c46bc240a1ac9b99974fcd4b735a6715ce99798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:14 +0000 Subject: [PATCH 370/814] docs: add an introduction to the system docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the frankly misleading quickstart section for a more rounded introduction section. This new section gives an overview of the accelerators as well as a high level introduction to some of the key features of the emulator. We also expand on a general form for a QEMU command line with a hopefully not too scary worked example of what this looks like. Acked-by: Richard Henderson Signed-off-by: Alex Bennée Reviewed-by: Kashyap Chamarthy Message-Id: <20230124180127.1881110-23-alex.bennee@linaro.org> --- docs/interop/live-block-operations.rst | 2 + docs/interop/qemu-qmp-ref.rst | 2 + docs/system/index.rst | 2 +- docs/system/introduction.rst | 220 +++++++++++++++++++++++++ docs/system/multi-process.rst | 2 + docs/system/quickstart.rst | 21 --- 6 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 docs/system/introduction.rst delete mode 100644 docs/system/quickstart.rst diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst index 135784ab33..691429c7af 100644 --- a/docs/interop/live-block-operations.rst +++ b/docs/interop/live-block-operations.rst @@ -4,6 +4,8 @@ This work is licensed under the terms of the GNU GPL, version 2 or later. See the COPYING file in the top-level directory. +.. _Live Block Operations: + ============================ Live Block Device Operations ============================ diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst index 357effd64f..f94614a0b2 100644 --- a/docs/interop/qemu-qmp-ref.rst +++ b/docs/interop/qemu-qmp-ref.rst @@ -1,3 +1,5 @@ +.. _QMP Ref: + QEMU QMP Reference Manual ========================= diff --git a/docs/system/index.rst b/docs/system/index.rst index 282b6ffb56..3605bbe1ce 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -12,7 +12,7 @@ or Hypervisor.Framework. .. toctree:: :maxdepth: 3 - quickstart + introduction invocation device-emulation keys diff --git a/docs/system/introduction.rst b/docs/system/introduction.rst new file mode 100644 index 0000000000..c8a9fe6c1d --- /dev/null +++ b/docs/system/introduction.rst @@ -0,0 +1,220 @@ +Introduction +============ + +Virtualisation Accelerators +--------------------------- + +QEMU's system emulation provides a virtual model of a machine (CPU, +memory and emulated devices) to run a guest OS. It supports a number +of hypervisors (known as accelerators) as well as a JIT known as the +Tiny Code Generator (TCG) capable of emulating many CPUs. + +.. list-table:: Supported Accelerators + :header-rows: 1 + + * - Accelerator + - Host OS + - Host Architectures + * - KVM + - Linux + - Arm (64 bit only), MIPS, PPC, RISC-V, s390x, x86 + * - Xen + - Linux (as dom0) + - Arm, x86 + * - Intel HAXM (hax) + - Linux, Windows + - x86 + * - Hypervisor Framework (hvf) + - MacOS + - x86 (64 bit only), Arm (64 bit only) + * - Windows Hypervisor Platform (wphx) + - Windows + - x86 + * - NetBSD Virtual Machine Monitor (nvmm) + - NetBSD + - x86 + * - Tiny Code Generator (tcg) + - Linux, other POSIX, Windows, MacOS + - Arm, x86, Loongarch64, MIPS, PPC, s390x, Sparc64 + +Feature Overview +---------------- + +System emulation provides a wide range of device models to emulate +various hardware components you may want to add to your machine. This +includes a wide number of VirtIO devices which are specifically tuned +for efficient operation under virtualisation. Some of the device +emulation can be offloaded from the main QEMU process using either +vhost-user (for VirtIO) or :ref:`Multi-process QEMU`. If the platform +supports it QEMU also supports directly passing devices through to +guest VMs to eliminate the device emulation overhead. See +:ref:`device-emulation` for more details. + +There is a full :ref:`featured block layer` +which allows for construction of complex storage topology which can be +stacked across multiple layers supporting redirection, networking, +snapshots and migration support. + +The flexible ``chardev`` system allows for handling IO from character +like devices using stdio, files, unix sockets and TCP networking. + +QEMU provides a number of management interfaces including a line based +:ref:`Human Monitor Protocol (HMP)` that allows you to +dynamically add and remove devices as well as introspect the system +state. The :ref:`QEMU Monitor Protocol` (QMP) is a well +defined, versioned, machine usable API that presents a rich interface +to other tools to create, control and manage Virtual Machines. This is +the interface used by higher level tools interfaces such as `Virt +Manager `_ using the `libvirt framework +`_. + +For the common accelerators QEMU, supported debugging with its +:ref:`gdbstub` which allows users to connect GDB and debug +system software images. + +Running +------- + +QEMU provides a rich and complex API which can be overwhelming to +understand. While some architectures can boot something with just a +disk image, those examples elide a lot of details with defaults that +may not be optimal for modern systems. + +For a non-x86 system where we emulate a broad range of machine types, +the command lines are generally more explicit in defining the machine +and boot behaviour. You will find often find example command lines in +the :ref:`system-targets-ref` section of the manual. + +While the project doesn't want to discourage users from using the +command line to launch VMs, we do want to highlight that there are a +number of projects dedicated to providing a more user friendly +experience. Those built around the ``libvirt`` framework can make use +of feature probing to build modern VM images tailored to run on the +hardware you have. + +That said, the general form of a QEMU command line can be expressed +as: + +.. parsed-literal:: + + $ |qemu_system| [machine opts] \\ + [cpu opts] \\ + [accelerator opts] \\ + [device opts] \\ + [backend opts] \\ + [interface opts] \\ + [boot opts] + +Most options will generate some help information. So for example: + +.. parsed-literal:: + + $ |qemu_system| -M help + +will list the machine types supported by that QEMU binary. ``help`` +can also be passed as an argument to another option. For example: + +.. parsed-literal:: + + $ |qemu_system| -device scsi-hd,help + +will list the arguments and their default values of additional options +that can control the behaviour of the ``scsi-hd`` device. + +.. list-table:: Options Overview + :header-rows: 1 + :widths: 10, 90 + + * - Options + - + * - Machine + - Define the machine type, amount of memory etc + * - CPU + - Type and number/topology of vCPUs. Most accelerators offer + a ``host`` cpu option which simply passes through your host CPU + configuration without filtering out any features. + * - Accelerator + - This will depend on the hypervisor you run. Note that the + default is TCG, which is purely emulated, so you must specify an + accelerator type to take advantage of hardware virtualization. + * - Devices + - Additional devices that are not defined by default with the + machine type. + * - Backends + - Backends are how QEMU deals with the guest's data, for example + how a block device is stored, how network devices see the + network or how a serial device is directed to the outside world. + * - Interfaces + - How the system is displayed, how it is managed and controlled or + debugged. + * - Boot + - How the system boots, via firmware or direct kernel boot. + +In the following example we first define a ``virt`` machine which is a +general purpose platform for running Aarch64 guests. We enable +virtualisation so we can use KVM inside the emulated guest. As the +``virt`` machine comes with some built in pflash devices we give them +names so we can override the defaults later. + +.. code:: + + $ qemu-system-aarch64 \ + -machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ + -m 4096 \ + +We then define the 4 vCPUs using the ``max`` option which gives us all +the Arm features QEMU is capable of emulating. We enable a more +emulation friendly implementation of Arm's pointer authentication +algorithm. We explicitly specify TCG acceleration even though QEMU +would default to it anyway. + +.. code:: + + -cpu max,pauth-impdef=on \ + -smp 4 \ + -accel tcg \ + +As the ``virt`` platform doesn't have any default network or storage +devices we need to define them. We give them ids so we can link them +with the backend later on. + +.. code:: + + -device virtio-net-pci,netdev=unet \ + -device virtio-scsi-pci \ + -device scsi-hd,drive=hd \ + +We connect the user-mode networking to our network device. As +user-mode networking isn't directly accessible from the outside world +we forward localhost port 2222 to the ssh port on the guest. + +.. code:: + + -netdev user,id=unet,hostfwd=tcp::2222-:22 \ + +We connect the guest visible block device to an LVM partition we have +set aside for our guest. + +.. code:: + + -blockdev driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/lvm-disk/debian-bullseye-arm64 \ + +We then tell QEMU to multiplex the :ref:`QEMU monitor` with the serial +port output (we can switch between the two using :ref:`keys in the +character backend multiplexer`). As there is no default graphical +device we disable the display as we can work entirely in the terminal. + +.. code:: + + -serial mon:stdio \ + -display none \ + +Finally we override the default firmware to ensure we have some +storage for EFI to persist its configuration. That firmware is +responsible for finding the disk, booting grub and eventually running +our system. + +.. code:: + + -blockdev node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true \ + -blockdev node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars diff --git a/docs/system/multi-process.rst b/docs/system/multi-process.rst index 210531ee17..16f0352416 100644 --- a/docs/system/multi-process.rst +++ b/docs/system/multi-process.rst @@ -1,3 +1,5 @@ +.. _Multi-process QEMU: + Multi-process QEMU ================== diff --git a/docs/system/quickstart.rst b/docs/system/quickstart.rst deleted file mode 100644 index 681678c86e..0000000000 --- a/docs/system/quickstart.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _pcsys_005fquickstart: - -Quick Start ------------ - -Download and uncompress a PC hard disk image with Linux installed (e.g. -``linux.img``) and type: - -.. parsed-literal:: - - |qemu_system| linux.img - -Linux should boot and give you a prompt. - -Users should be aware the above example elides a lot of the complexity -of setting up a VM with x86_64 specific defaults and assumes the -first non switch argument is a PC compatible disk image with a boot -sector. For a non-x86 system where we emulate a broad range of machine -types, the command lines are generally more explicit in defining the -machine and boot behaviour. You will find more example command lines -in the :ref:`system-targets-ref` section of the manual. From 978c2bf97b2f8b0938dc6570c46275ed8d8e96f8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 24 Jan 2023 18:01:15 +0000 Subject: [PATCH 371/814] semihosting: Write back semihosting data before completion callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'lock_user' allocates a host buffer to shadow a target buffer, 'unlock_user' copies that host buffer back to the target and frees the host memory. If the completion function uses the target buffer, it must be called after unlock_user to ensure the data are present. This caused the arm-compatible TARGET_SYS_READC to fail as the completion function, common_semi_readc_cb, pulled data from the target buffer which would not have been gotten the console data. I decided to fix all instances of this pattern instead of just the console_read function to make things consistent and potentially fix bugs in other cases. Signed-off-by: Keith Packard Reviewed-by: Richard Henderson Message-Id: <20221012014822.1242170-1-keithp@keithp.com> Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230124180127.1881110-24-alex.bennee@linaro.org> --- semihosting/syscalls.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index 5893c760c5..ba28194b59 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -319,11 +319,11 @@ static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, } ret = RETRY_ON_EINTR(read(gf->hostfd, ptr, len)); if (ret == -1) { - complete(cs, -1, errno); unlock_user(ptr, buf, 0); + complete(cs, -1, errno); } else { - complete(cs, ret, 0); unlock_user(ptr, buf, ret); + complete(cs, ret, 0); } } @@ -339,8 +339,8 @@ static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = write(gf->hostfd, ptr, len); - complete(cs, ret, ret == -1 ? errno : 0); unlock_user(ptr, buf, 0); + complete(cs, ret, ret == -1 ? errno : 0); } static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete, @@ -426,8 +426,8 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, ret = -1; } } - complete(cs, ret, err); unlock_user(name, fname, 0); + complete(cs, ret, err); } static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, @@ -444,8 +444,8 @@ static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, } ret = remove(p); - complete(cs, ret, ret ? errno : 0); unlock_user(p, fname, 0); + complete(cs, ret, ret ? errno : 0); } static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, @@ -469,9 +469,9 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, } ret = rename(ostr, nstr); - complete(cs, ret, ret ? errno : 0); unlock_user(ostr, oname, 0); unlock_user(nstr, nname, 0); + complete(cs, ret, ret ? errno : 0); } static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, @@ -488,8 +488,8 @@ static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, } ret = system(p); - complete(cs, ret, ret == -1 ? errno : 0); unlock_user(p, cmd, 0); + complete(cs, ret, ret == -1 ? errno : 0); } static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, @@ -554,8 +554,8 @@ static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, } memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); gf->staticfile.off += len; - complete(cs, len, 0); unlock_user(ptr, buf, len); + complete(cs, len, 0); } static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, @@ -608,8 +608,8 @@ static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = qemu_semihosting_console_read(cs, ptr, len); - complete(cs, ret, 0); unlock_user(ptr, buf, ret); + complete(cs, ret, 0); } static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, @@ -624,8 +624,8 @@ static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = qemu_semihosting_console_write(ptr, len); - complete(cs, ret ? ret : -1, ret ? 0 : EIO); unlock_user(ptr, buf, 0); + complete(cs, ret ? ret : -1, ret ? 0 : EIO); } static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete, From 0bccdb42df66b697e0a4681c2ad4f10eccef5330 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Tue, 24 Jan 2023 18:01:16 +0000 Subject: [PATCH 372/814] semihosting: add O_BINARY flag in host_open for NT compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows open(2) implementation opens files in text mode by default and needs a Windows-only O_BINARY flag to open files as binary. QEMU already knows about that flag in osdep and it is defined to 0 on non-Windows, so we can just add it to the host_flags for better compatibility. Signed-off-by: Evgeny Iakovlev Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bin Meng Message-Id: <20230106102018.20520-1-eiakovlev@linux.microsoft.com> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-25-alex.bennee@linaro.org> --- semihosting/syscalls.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index ba28194b59..e89992cf90 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -253,7 +253,7 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, { CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; char *p; - int ret, host_flags; + int ret, host_flags = O_BINARY; ret = validate_lock_user_string(&p, cs, fname, fname_len); if (ret < 0) { @@ -262,11 +262,11 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, } if (gdb_flags & GDB_O_WRONLY) { - host_flags = O_WRONLY; + host_flags |= O_WRONLY; } else if (gdb_flags & GDB_O_RDWR) { - host_flags = O_RDWR; + host_flags |= O_RDWR; } else { - host_flags = O_RDONLY; + host_flags |= O_RDONLY; } if (gdb_flags & GDB_O_CREAT) { host_flags |= O_CREAT; From d54c6d3b5ddc0555f8d3bb6b0ba59da1f59b18f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 24 Jan 2023 18:01:17 +0000 Subject: [PATCH 373/814] tests/tcg: add memory-sve test for aarch64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be helpful in debugging problems with tracking SVE memory accesses via the TCG plugins system. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Cc: Robert Henry Cc: Aaron Lindsay Message-Id: <20230124180127.1881110-26-alex.bennee@linaro.org> --- tests/tcg/aarch64/Makefile.softmmu-target | 7 +++++++ tests/tcg/aarch64/system/boot.S | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index a1368905f5..df9747bae8 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -36,6 +36,13 @@ config-cc.mak: Makefile memory: CFLAGS+=-DCHECK_UNALIGNED=1 +memory-sve: memory.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) + +memory-sve: CFLAGS+=-DCHECK_UNALIGNED=1 -march=armv8.1-a+sve -O3 -fno-tree-loop-distribute-patterns + +TESTS+=memory-sve + # Running QEMU_BASE_MACHINE=-M virt -cpu max -display none QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S index e190b1efa6..f136363d2a 100644 --- a/tests/tcg/aarch64/system/boot.S +++ b/tests/tcg/aarch64/system/boot.S @@ -179,12 +179,13 @@ __start: isb /* - * Enable FP registers. The standard C pre-amble will be + * Enable FP/SVE registers. The standard C pre-amble will be * saving these and A-profile compilers will use AdvSIMD * registers unless we tell it not to. */ mrs x0, cpacr_el1 orr x0, x0, #(3 << 20) + orr x0, x0, #(3 << 16) msr cpacr_el1, x0 /* Setup some stack space and enter the test code. From 4731f89b3b9690efccb6084b9fee43083669de14 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:18 +0000 Subject: [PATCH 374/814] cpu: free cpu->tb_jmp_cache with RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the appended use-after-free. The root cause is that during tb invalidation we use CPU_FOREACH, and therefore to safely free a vCPU we must wait for an RCU grace period to elapse. $ x86_64-linux-user/qemu-x86_64 tests/tcg/x86_64-linux-user/munmap-pthread ================================================================= ==1800604==ERROR: AddressSanitizer: heap-use-after-free on address 0x62d0005f7418 at pc 0x5593da6704eb bp 0x7f4961a7ac70 sp 0x7f4961a7ac60 READ of size 8 at 0x62d0005f7418 thread T2 #0 0x5593da6704ea in tb_jmp_cache_inval_tb ../accel/tcg/tb-maint.c:244 #1 0x5593da6704ea in do_tb_phys_invalidate ../accel/tcg/tb-maint.c:290 #2 0x5593da670631 in tb_phys_invalidate__locked ../accel/tcg/tb-maint.c:306 #3 0x5593da670631 in tb_invalidate_phys_page_range__locked ../accel/tcg/tb-maint.c:542 #4 0x5593da67106d in tb_invalidate_phys_range ../accel/tcg/tb-maint.c:614 #5 0x5593da6a64d4 in target_munmap ../linux-user/mmap.c:766 #6 0x5593da6dba05 in do_syscall1 ../linux-user/syscall.c:10105 #7 0x5593da6f564c in do_syscall ../linux-user/syscall.c:13329 #8 0x5593da49e80c in cpu_loop ../linux-user/x86_64/../i386/cpu_loop.c:233 #9 0x5593da6be28c in clone_func ../linux-user/syscall.c:6633 #10 0x7f496231cb42 in start_thread nptl/pthread_create.c:442 #11 0x7f49623ae9ff (/lib/x86_64-linux-gnu/libc.so.6+0x1269ff) 0x62d0005f7418 is located 28696 bytes inside of 32768-byte region [0x62d0005f0400,0x62d0005f8400) freed by thread T148 here: #0 0x7f49627b6460 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x5593da5ac057 in cpu_exec_unrealizefn ../cpu.c:180 #2 0x5593da81f851 (/home/cota/src/qemu/build/qemu-x86_64+0x484851) Signed-off-by: Emilio Cota Reviewed-by: Richard Henderson Message-Id: <20230111151628.320011-2-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-27-alex.bennee@linaro.org> --- accel/tcg/cpu-exec.c | 3 +-- accel/tcg/tb-jmp-cache.h | 1 + cpu.c | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 04cd1f3092..25ec73ef9a 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -1064,13 +1064,12 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp) /* undo the initializations in reverse order */ void tcg_exec_unrealizefn(CPUState *cpu) { - qemu_plugin_vcpu_exit_hook(cpu); #ifndef CONFIG_USER_ONLY tcg_iommu_free_notifier_list(cpu); #endif /* !CONFIG_USER_ONLY */ tlb_destroy(cpu); - g_free(cpu->tb_jmp_cache); + g_free_rcu(cpu->tb_jmp_cache, rcu); } #ifndef CONFIG_USER_ONLY diff --git a/accel/tcg/tb-jmp-cache.h b/accel/tcg/tb-jmp-cache.h index ff5ffc8fc2..b3f6e78835 100644 --- a/accel/tcg/tb-jmp-cache.h +++ b/accel/tcg/tb-jmp-cache.h @@ -18,6 +18,7 @@ * a load_acquire/store_release to 'tb'. */ struct CPUJumpCache { + struct rcu_head rcu; struct { TranslationBlock *tb; #if TARGET_TB_PCREL diff --git a/cpu.c b/cpu.c index 4a7d865427..21cf809614 100644 --- a/cpu.c +++ b/cpu.c @@ -176,11 +176,20 @@ void cpu_exec_unrealizefn(CPUState *cpu) vmstate_unregister(NULL, &vmstate_cpu_common, cpu); } #endif + + /* Call the plugin hook before clearing cpu->cpu_index in cpu_list_remove */ if (tcg_enabled()) { - tcg_exec_unrealizefn(cpu); + qemu_plugin_vcpu_exit_hook(cpu); } cpu_list_remove(cpu); + /* + * Now that the vCPU has been removed from the RCU list, we can call + * tcg_exec_unrealizefn, which may free fields using call_rcu. + */ + if (tcg_enabled()) { + tcg_exec_unrealizefn(cpu); + } } /* From def48dddcfb2b8d9ef64ba5e6845ace006d30d27 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:19 +0000 Subject: [PATCH 375/814] util/qht: add missing atomic_set(hashes[i]) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to add this one in "a890643958 util/qht: atomically set b->hashes". Detected with tsan. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Signed-off-by: Emilio Cota Message-Id: <20230111151628.320011-3-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-28-alex.bennee@linaro.org> --- util/qht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/qht.c b/util/qht.c index 065fc501f4..15866299e6 100644 --- a/util/qht.c +++ b/util/qht.c @@ -688,7 +688,7 @@ static inline void qht_bucket_remove_entry(struct qht_bucket *orig, int pos) int i; if (qht_entry_is_last(orig, pos)) { - orig->hashes[pos] = 0; + qatomic_set(&orig->hashes[pos], 0); qatomic_set(&orig->pointers[pos], NULL); return; } From 047e2bd3383ba488f928b335f9d99cef3a216418 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:20 +0000 Subject: [PATCH 376/814] thread: de-const qemu_spin_destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Emilio Cota Reviewed-by: Richard Henderson Message-Id: <20230111151628.320011-4-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-29-alex.bennee@linaro.org> --- include/qemu/thread.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 7c6703bce3..7841084199 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -237,11 +237,10 @@ static inline void qemu_spin_init(QemuSpin *spin) #endif } -/* const parameter because the only purpose here is the TSAN annotation */ -static inline void qemu_spin_destroy(const QemuSpin *spin) +static inline void qemu_spin_destroy(QemuSpin *spin) { #ifdef CONFIG_TSAN - __tsan_mutex_destroy((void *)spin, __tsan_mutex_not_static); + __tsan_mutex_destroy(spin, __tsan_mutex_not_static); #endif } From 68f7b2be532ad5b134cd0053173641cf52cfa247 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:21 +0000 Subject: [PATCH 377/814] util/qht: use striped locks under TSAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes this tsan crash, easy to reproduce with any large enough program: $ tests/unit/test-qht 1..2 ThreadSanitizer: CHECK failed: sanitizer_deadlock_detector.h:67 "((n_all_locks_)) < (((sizeof(all_locks_with_contexts_)/sizeof((all_locks_with_contexts_)[0]))))" (0x40, 0x40) (tid=1821568) #0 __tsan::CheckUnwind() ../../../../src/libsanitizer/tsan/tsan_rtl.cpp:353 (libtsan.so.2+0x90034) #1 __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_termination.cpp:86 (libtsan.so.2+0xca555) #2 __sanitizer::DeadlockDetectorTLS<__sanitizer::TwoLevelBitVector<1ul, __sanitizer::BasicBitVector > >::addLock(unsigned long, unsigned long, unsigned int) ../../../../src/libsanitizer/sanitizer_common/sanitizer_deadlock_detector.h:67 (libtsan.so.2+0xb3616) #3 __sanitizer::DeadlockDetectorTLS<__sanitizer::TwoLevelBitVector<1ul, __sanitizer::BasicBitVector > >::addLock(unsigned long, unsigned long, unsigned int) ../../../../src/libsanitizer/sanitizer_common/sanitizer_deadlock_detector.h:59 (libtsan.so.2+0xb3616) #4 __sanitizer::DeadlockDetector<__sanitizer::TwoLevelBitVector<1ul, __sanitizer::BasicBitVector > >::onLockAfter(__sanitizer::DeadlockDetectorTLS<__sanitizer::TwoLevelBitVector<1ul, __sanitizer::BasicBitVector > >*, unsigned long, unsigned int) ../../../../src/libsanitizer/sanitizer_common/sanitizer_deadlock_detector.h:216 (libtsan.so.2+0xb3616) #5 __sanitizer::DD::MutexAfterLock(__sanitizer::DDCallback*, __sanitizer::DDMutex*, bool, bool) ../../../../src/libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cpp:169 (libtsan.so.2+0xb3616) #6 __tsan::MutexPostLock(__tsan::ThreadState*, unsigned long, unsigned long, unsigned int, int) ../../../../src/libsanitizer/tsan/tsan_rtl_mutex.cpp:200 (libtsan.so.2+0xa3382) #7 __tsan_mutex_post_lock ../../../../src/libsanitizer/tsan/tsan_interface_ann.cpp:384 (libtsan.so.2+0x76bc3) #8 qemu_spin_lock /home/cota/src/qemu/include/qemu/thread.h:259 (test-qht+0x44a97) #9 qht_map_lock_buckets ../util/qht.c:253 (test-qht+0x44a97) #10 do_qht_iter ../util/qht.c:809 (test-qht+0x45f33) #11 qht_iter ../util/qht.c:821 (test-qht+0x45f33) #12 iter_check ../tests/unit/test-qht.c:121 (test-qht+0xe473) #13 qht_do_test ../tests/unit/test-qht.c:202 (test-qht+0xe473) #14 qht_test ../tests/unit/test-qht.c:240 (test-qht+0xe7c1) #15 test_default ../tests/unit/test-qht.c:246 (test-qht+0xe828) #16 (libglib-2.0.so.0+0x7daed) #17 (libglib-2.0.so.0+0x7d80a) #18 (libglib-2.0.so.0+0x7d80a) #19 g_test_run_suite (libglib-2.0.so.0+0x7dfe9) #20 g_test_run (libglib-2.0.so.0+0x7e055) #21 main ../tests/unit/test-qht.c:259 (test-qht+0xd2c6) #22 __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 (libc.so.6+0x29d8f) #23 __libc_start_main_impl ../csu/libc-start.c:392 (libc.so.6+0x29e3f) #24 _start (test-qht+0xdb44) Signed-off-by: Emilio Cota Reviewed-by: Richard Henderson Message-Id: <20230111151628.320011-5-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-30-alex.bennee@linaro.org> --- util/qht.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/util/qht.c b/util/qht.c index 15866299e6..92c6b78759 100644 --- a/util/qht.c +++ b/util/qht.c @@ -151,6 +151,22 @@ struct qht_bucket { QEMU_BUILD_BUG_ON(sizeof(struct qht_bucket) > QHT_BUCKET_ALIGN); +/* + * Under TSAN, we use striped locks instead of one lock per bucket chain. + * This avoids crashing under TSAN, since TSAN aborts the program if more than + * 64 locks are held (this is a hardcoded limit in TSAN). + * When resizing a QHT we grab all the buckets' locks, which can easily + * go over TSAN's limit. By using striped locks, we avoid this problem. + * + * Note: this number must be a power of two for easy index computation. + */ +#define QHT_TSAN_BUCKET_LOCKS_BITS 4 +#define QHT_TSAN_BUCKET_LOCKS (1 << QHT_TSAN_BUCKET_LOCKS_BITS) + +struct qht_tsan_lock { + QemuSpin lock; +} QEMU_ALIGNED(QHT_BUCKET_ALIGN); + /** * struct qht_map - structure to track an array of buckets * @rcu: used by RCU. Keep it as the top field in the struct to help valgrind @@ -160,6 +176,7 @@ QEMU_BUILD_BUG_ON(sizeof(struct qht_bucket) > QHT_BUCKET_ALIGN); * @n_added_buckets: number of added (i.e. "non-head") buckets * @n_added_buckets_threshold: threshold to trigger an upward resize once the * number of added buckets surpasses it. + * @tsan_bucket_locks: Array of striped locks to be used only under TSAN. * * Buckets are tracked in what we call a "map", i.e. this structure. */ @@ -169,6 +186,9 @@ struct qht_map { size_t n_buckets; size_t n_added_buckets; size_t n_added_buckets_threshold; +#ifdef CONFIG_TSAN + struct qht_tsan_lock tsan_bucket_locks[QHT_TSAN_BUCKET_LOCKS]; +#endif }; /* trigger a resize when n_added_buckets > n_buckets / div */ @@ -229,10 +249,56 @@ static inline size_t qht_elems_to_buckets(size_t n_elems) return pow2ceil(n_elems / QHT_BUCKET_ENTRIES); } -static inline void qht_head_init(struct qht_bucket *b) +/* + * When using striped locks (i.e. under TSAN), we have to be careful not + * to operate on the same lock twice (e.g. when iterating through all buckets). + * We achieve this by operating only on each stripe's first matching lock. + */ +static inline void qht_do_if_first_in_stripe(struct qht_map *map, + struct qht_bucket *b, + void (*func)(QemuSpin *spin)) +{ +#ifdef CONFIG_TSAN + unsigned long bucket_idx = b - map->buckets; + bool is_first_in_stripe = (bucket_idx >> QHT_TSAN_BUCKET_LOCKS_BITS) == 0; + if (is_first_in_stripe) { + unsigned long lock_idx = bucket_idx & (QHT_TSAN_BUCKET_LOCKS - 1); + func(&map->tsan_bucket_locks[lock_idx].lock); + } +#else + func(&b->lock); +#endif +} + +static inline void qht_bucket_lock_do(struct qht_map *map, + struct qht_bucket *b, + void (*func)(QemuSpin *lock)) +{ +#ifdef CONFIG_TSAN + unsigned long bucket_idx = b - map->buckets; + unsigned long lock_idx = bucket_idx & (QHT_TSAN_BUCKET_LOCKS - 1); + func(&map->tsan_bucket_locks[lock_idx].lock); +#else + func(&b->lock); +#endif +} + +static inline void qht_bucket_lock(struct qht_map *map, + struct qht_bucket *b) +{ + qht_bucket_lock_do(map, b, qemu_spin_lock); +} + +static inline void qht_bucket_unlock(struct qht_map *map, + struct qht_bucket *b) +{ + qht_bucket_lock_do(map, b, qemu_spin_unlock); +} + +static inline void qht_head_init(struct qht_map *map, struct qht_bucket *b) { memset(b, 0, sizeof(*b)); - qemu_spin_init(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_init); seqlock_init(&b->sequence); } @@ -250,7 +316,7 @@ static void qht_map_lock_buckets(struct qht_map *map) for (i = 0; i < map->n_buckets; i++) { struct qht_bucket *b = &map->buckets[i]; - qemu_spin_lock(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_lock); } } @@ -261,7 +327,7 @@ static void qht_map_unlock_buckets(struct qht_map *map) for (i = 0; i < map->n_buckets; i++) { struct qht_bucket *b = &map->buckets[i]; - qemu_spin_unlock(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_unlock); } } @@ -308,7 +374,7 @@ void qht_map_lock_buckets__no_stale(struct qht *ht, struct qht_map **pmap) * Get a head bucket and lock it, making sure its parent map is not stale. * @pmap is filled with a pointer to the bucket's parent map. * - * Unlock with qemu_spin_unlock(&b->lock). + * Unlock with qht_bucket_unlock. * * Note: callers cannot have ht->lock held. */ @@ -322,18 +388,18 @@ struct qht_bucket *qht_bucket_lock__no_stale(struct qht *ht, uint32_t hash, map = qatomic_rcu_read(&ht->map); b = qht_map_to_bucket(map, hash); - qemu_spin_lock(&b->lock); + qht_bucket_lock(map, b); if (likely(!qht_map_is_stale__locked(ht, map))) { *pmap = map; return b; } - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); /* we raced with a resize; acquire ht->lock to see the updated ht->map */ qht_lock(ht); map = ht->map; b = qht_map_to_bucket(map, hash); - qemu_spin_lock(&b->lock); + qht_bucket_lock(map, b); qht_unlock(ht); *pmap = map; return b; @@ -345,12 +411,13 @@ static inline bool qht_map_needs_resize(const struct qht_map *map) map->n_added_buckets_threshold; } -static inline void qht_chain_destroy(const struct qht_bucket *head) +static inline void qht_chain_destroy(struct qht_map *map, + struct qht_bucket *head) { struct qht_bucket *curr = head->next; struct qht_bucket *prev; - qemu_spin_destroy(&head->lock); + qht_do_if_first_in_stripe(map, head, qemu_spin_destroy); while (curr) { prev = curr; curr = curr->next; @@ -364,7 +431,7 @@ static void qht_map_destroy(struct qht_map *map) size_t i; for (i = 0; i < map->n_buckets; i++) { - qht_chain_destroy(&map->buckets[i]); + qht_chain_destroy(map, &map->buckets[i]); } qemu_vfree(map->buckets); g_free(map); @@ -390,7 +457,7 @@ static struct qht_map *qht_map_create(size_t n_buckets) map->buckets = qemu_memalign(QHT_BUCKET_ALIGN, sizeof(*map->buckets) * n_buckets); for (i = 0; i < n_buckets; i++) { - qht_head_init(&map->buckets[i]); + qht_head_init(map, &map->buckets[i]); } return map; } @@ -638,7 +705,7 @@ bool qht_insert(struct qht *ht, void *p, uint32_t hash, void **existing) b = qht_bucket_lock__no_stale(ht, hash, &map); prev = qht_insert__locked(ht, map, b, p, hash, &needs_resize); qht_bucket_debug__locked(b); - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); if (unlikely(needs_resize) && ht->mode & QHT_MODE_AUTO_RESIZE) { qht_grow_maybe(ht); @@ -749,7 +816,7 @@ bool qht_remove(struct qht *ht, const void *p, uint32_t hash) b = qht_bucket_lock__no_stale(ht, hash, &map); ret = qht_remove__locked(b, p, hash); qht_bucket_debug__locked(b); - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); return ret; } From 2bbbc1be8d9a21b25d0c80b9a7345074d54abd51 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:22 +0000 Subject: [PATCH 378/814] plugins: make qemu_plugin_user_exit's locking order consistent with fork_start's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To fix potential deadlocks as reported by tsan. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Emilio Cota Message-Id: <20230111151628.320011-6-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-31-alex.bennee@linaro.org> --- plugins/core.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/core.c b/plugins/core.c index ccb770a485..728bacef95 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -500,10 +500,17 @@ void qemu_plugin_user_exit(void) enum qemu_plugin_event ev; CPUState *cpu; - QEMU_LOCK_GUARD(&plugin.lock); - + /* + * Locking order: we must acquire locks in an order that is consistent + * with the one in fork_start(). That is: + * - start_exclusive(), which acquires qemu_cpu_list_lock, + * must be called before acquiring plugin.lock. + * - tb_flush(), which acquires mmap_lock(), must be called + * while plugin.lock is not held. + */ start_exclusive(); + qemu_rec_mutex_lock(&plugin.lock); /* un-register all callbacks except the final AT_EXIT one */ for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) { if (ev != QEMU_PLUGIN_EV_ATEXIT) { @@ -513,13 +520,12 @@ void qemu_plugin_user_exit(void) } } } - - tb_flush(current_cpu); - CPU_FOREACH(cpu) { qemu_plugin_disable_mem_helpers(cpu); } + qemu_rec_mutex_unlock(&plugin.lock); + tb_flush(current_cpu); end_exclusive(); /* now it's safe to handle the exit case */ From 3fd62e73ad8193b58a1bc15ad6f6d8b4f284f6a7 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:23 +0000 Subject: [PATCH 379/814] plugins: fix optimization in plugin_gen_disable_mem_helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were mistakenly checking tcg_ctx->plugin_insn as a canary to know whether the TB had emitted helpers that might have accessed memory. The problem is that tcg_ctx->plugin_insn gets updated on every instruction in the TB, which results in us wrongly performing the optimization (i.e. not clearing cpu->plugin_mem_cbs) way too often, since it's not rare that the last instruction in the TB doesn't use helpers. Fix it by tracking a per-TB canary. While at it, expand documentation. Related: #1381 Signed-off-by: Emilio Cota Message-Id: <20230108164731.61469-2-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-32-alex.bennee@linaro.org> --- accel/tcg/plugin-gen.c | 26 ++++++++++++++++++-------- include/qemu/plugin.h | 7 +++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index c7d6514840..17a686bd9e 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -579,7 +579,8 @@ static void inject_mem_helper(TCGOp *begin_op, GArray *arr) * is possible that the code we generate after the instruction is * dead, we also add checks before generating tb_exit etc. */ -static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn, +static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb, + struct qemu_plugin_insn *plugin_insn, TCGOp *begin_op) { GArray *cbs[2]; @@ -599,6 +600,7 @@ static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn, rm_ops(begin_op); return; } + ptb->mem_helper = true; arr = g_array_sized_new(false, false, sizeof(struct qemu_plugin_dyn_cb), n_cbs); @@ -626,15 +628,22 @@ void plugin_gen_disable_mem_helpers(void) { TCGv_ptr ptr; - if (likely(tcg_ctx->plugin_insn == NULL || - !tcg_ctx->plugin_insn->mem_helper)) { + /* + * We could emit the clearing unconditionally and be done. However, this can + * be wasteful if for instance plugins don't track memory accesses, or if + * most TBs don't use helpers. Instead, emit the clearing iff the TB calls + * helpers that might access guest memory. + * + * Note: we do not reset plugin_tb->mem_helper here; a TB might have several + * exit points, and we want to emit the clearing from all of them. + */ + if (!tcg_ctx->plugin_tb->mem_helper) { return; } ptr = tcg_const_ptr(NULL); tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env)); tcg_temp_free_ptr(ptr); - tcg_ctx->plugin_insn->mem_helper = false; } static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb, @@ -682,14 +691,14 @@ static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb, inject_inline_cb(cbs, begin_op, op_rw); } -static void plugin_gen_enable_mem_helper(const struct qemu_plugin_tb *ptb, +static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb, TCGOp *begin_op, int insn_idx) { struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx); - inject_mem_enable_helper(insn, begin_op); + inject_mem_enable_helper(ptb, insn, begin_op); } -static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb, +static void plugin_gen_disable_mem_helper(struct qemu_plugin_tb *ptb, TCGOp *begin_op, int insn_idx) { struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx); @@ -750,7 +759,7 @@ static void pr_ops(void) #endif } -static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb) +static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb) { TCGOp *op; int insn_idx = -1; @@ -870,6 +879,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db, ptb->haddr1 = db->host_addr[0]; ptb->haddr2 = NULL; ptb->mem_only = mem_only; + ptb->mem_helper = false; plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB); } diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index a772e14193..e0ebedef84 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -118,7 +118,10 @@ struct qemu_plugin_insn { void *haddr; GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES]; bool calls_helpers; + + /* if set, the instruction calls helpers that might access guest memory */ bool mem_helper; + bool mem_only; }; @@ -158,6 +161,10 @@ struct qemu_plugin_tb { void *haddr1; void *haddr2; bool mem_only; + + /* if set, the TB calls helpers that might access guest memory */ + bool mem_helper; + GArray *cbs[PLUGIN_N_CB_SUBTYPES]; }; From 0f92d94ae37952ed3e6771bc429de4b739eb6ca3 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:24 +0000 Subject: [PATCH 380/814] translator: always pair plugin_gen_insn_{start, end} calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: #1381 Signed-off-by: Emilio Cota Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230108164731.61469-3-cota@braap.org> Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-33-alex.bennee@linaro.org> --- accel/tcg/translator.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 061519691f..ef5193c67e 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -100,19 +100,24 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns, ops->translate_insn(db, cpu); } - /* Stop translation if translate_insn so indicated. */ - if (db->is_jmp != DISAS_NEXT) { - break; - } - /* * We can't instrument after instructions that change control * flow although this only really affects post-load operations. + * + * Calling plugin_gen_insn_end() before we possibly stop translation + * is important. Even if this ends up as dead code, plugin generation + * needs to see a matching plugin_gen_insn_{start,end}() pair in order + * to accurately track instrumented helpers that might access memory. */ if (plugin_enabled) { plugin_gen_insn_end(); } + /* Stop translation if translate_insn so indicated. */ + if (db->is_jmp != DISAS_NEXT) { + break; + } + /* Stop translation if the output buffer is full, or we have executed all of the allowed instructions. */ if (tcg_op_buf_full() || db->num_insns >= db->max_insns) { From 17083f6fa6e02326f1c1e8b67b8b282480d013d2 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:25 +0000 Subject: [PATCH 381/814] tcg: exclude non-memory effecting helpers from instrumentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are actually a whole bunch of helpers that don't affect memory that we shouldn't instrument. They are helpfully identified by the TCG_CALL_NO_SIDE_EFFECTS flag which marks out lookup_tb_ptr as well as a lot of the maths helpers. To avoid the string compare we introduce a new flag for plugin internals so we skip that too. Related: #1381 Signed-off-by: Emilio Cota Message-Id: <20230108164731.61469-4-cota@braap.org> [AJB: updated to skip all no SE plugins, add flag for plugin helper] Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20230124180127.1881110-34-alex.bennee@linaro.org> --- accel/tcg/plugin-helpers.h | 4 ++-- include/tcg/tcg.h | 2 ++ tcg/tcg.c | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h index 9829abe4a9..8e685e0654 100644 --- a/accel/tcg/plugin-helpers.h +++ b/accel/tcg/plugin-helpers.h @@ -1,4 +1,4 @@ #ifdef CONFIG_PLUGIN -DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb, TCG_CALL_NO_RWG, void, i32, ptr) -DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG, void, i32, i32, i64, ptr) +DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr) +DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, i32, i64, ptr) #endif diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 6f497172f8..8dc291d030 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -405,6 +405,8 @@ typedef TCGv_ptr TCGv_env; #define TCG_CALL_NO_SIDE_EFFECTS 0x0004 /* Helper is G_NORETURN. */ #define TCG_CALL_NO_RETURN 0x0008 +/* Helper is part of Plugins. */ +#define TCG_CALL_PLUGIN 0x0010 /* convenience version of most used call flags */ #define TCG_CALL_NO_RWG TCG_CALL_NO_READ_GLOBALS diff --git a/tcg/tcg.c b/tcg/tcg.c index d502327be2..fd557d55d3 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1674,8 +1674,10 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) op = tcg_op_alloc(INDEX_op_call, total_args); #ifdef CONFIG_PLUGIN - /* detect non-plugin helpers */ - if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { + /* Flag helpers that may affect guest state */ + if (tcg_ctx->plugin_insn && + !(info->flags & TCG_CALL_PLUGIN) && + !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { tcg_ctx->plugin_insn->calls_helpers = true; } #endif From 882f5b1b4418cfa8f65ff2be52286247db40d152 Mon Sep 17 00:00:00 2001 From: Emilio Cota Date: Tue, 24 Jan 2023 18:01:26 +0000 Subject: [PATCH 382/814] cpu-exec: assert that plugin_mem_cbs is NULL after execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: #1381 Signed-off-by: Emilio Cota Message-Id: <20230108165107.62488-1-cota@braap.org> [AJB: manually applied follow-up fix] Signed-off-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230124180127.1881110-35-alex.bennee@linaro.org> --- accel/tcg/cpu-exec.c | 2 ++ include/qemu/plugin.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 25ec73ef9a..9c857eeb07 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -504,6 +504,7 @@ static void cpu_exec_exit(CPUState *cpu) if (cc->tcg_ops->cpu_exec_exit) { cc->tcg_ops->cpu_exec_exit(cpu); } + QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL); } void cpu_exec_step_atomic(CPUState *cpu) @@ -980,6 +981,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit); + QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL); /* Try to align the host and virtual clocks if the guest is in advance */ align_clocks(sc, cpu); diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index e0ebedef84..fb338ba576 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -59,6 +59,8 @@ get_plugin_meminfo_rw(qemu_plugin_meminfo_t i) #ifdef CONFIG_PLUGIN extern QemuOptsList qemu_plugin_opts; +#define QEMU_PLUGIN_ASSERT(cond) g_assert(cond) + static inline void qemu_plugin_add_opts(void) { qemu_add_opts(&qemu_plugin_opts); @@ -250,6 +252,8 @@ void qemu_plugin_user_postfork(bool is_child); #else /* !CONFIG_PLUGIN */ +#define QEMU_PLUGIN_ASSERT(cond) + static inline void qemu_plugin_add_opts(void) { } From f45549233f67e5fd3038d2c886ef7de876c8ff01 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 24 Jan 2023 18:01:27 +0000 Subject: [PATCH 383/814] plugins: Iterate on cb_lists in qemu_plugin_user_exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than iterate over all plugins for all events, iterate over plugins that have registered a given event. Signed-off-by: Richard Henderson Message-Id: <20230117035701.168514-4-richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20230124180127.1881110-36-alex.bennee@linaro.org> --- plugins/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/core.c b/plugins/core.c index 728bacef95..e04ffa1ba4 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -514,9 +514,10 @@ void qemu_plugin_user_exit(void) /* un-register all callbacks except the final AT_EXIT one */ for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) { if (ev != QEMU_PLUGIN_EV_ATEXIT) { - struct qemu_plugin_ctx *ctx; - QTAILQ_FOREACH(ctx, &plugin.ctxs, entry) { - plugin_unregister_cb__locked(ctx, ev); + struct qemu_plugin_cb *cb, *next; + + QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { + plugin_unregister_cb__locked(cb->ctx, ev); } } } From b3ca9646b9a5c44dfd110c5db9b4a8b8497de34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 2 Feb 2023 13:25:27 +0000 Subject: [PATCH 384/814] gitlab: cut even more from cross-win64-system build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This keeps hitting the time limits so cut even more from the list. Signed-off-by: Alex Bennée --- .gitlab-ci.d/crossbuilds.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 8dbbb8f881..74d6259b90 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -187,7 +187,9 @@ cross-win64-system: job: win64-fedora-cross-container variables: IMAGE: fedora-win64-cross - CROSS_SKIP_TARGETS: or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu + CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu + m68k-softmmu microblazeel-softmmu nios2-softmmu + or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu tricore-softmmu xtensaeb-softmmu artifacts: paths: From b862888c53033c66f0ac4af27718f7971dcd713c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 19 Jan 2023 10:15:44 +0100 Subject: [PATCH 385/814] MAINTAINERS: Cover userfaultfd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0e9b5cd6b2 "migration: introduce UFFD-WP low-level interface helpers" added util/userfaultfd.c without covering it in MAINTAINERS. Add it to section "Migration". Signed-off-by: Markus Armbruster Message-Id: <20230119091545.3116376-2-armbru@redhat.com> Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index c581c11a64..5288eb8271 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3088,6 +3088,7 @@ S: Maintained F: hw/core/vmstate-if.c F: include/hw/vmstate-if.h F: include/migration/ +F: include/qemu/userfaultfd.h F: migration/ F: scripts/vmstate-static-checker.py F: tests/vmstate-static-checker-data/ @@ -3095,6 +3096,7 @@ F: tests/qtest/migration-test.c F: docs/devel/migration.rst F: qapi/migration.json F: tests/migration/ +F: util/userfaultfd.c D-Bus M: Marc-André Lureau From 75e5519a139e57e4b953a9336cb87ad12f8a3719 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 19 Jan 2023 10:15:45 +0100 Subject: [PATCH 386/814] MAINTAINERS: Cover include/sysemu/accel-blocker.h Commit bd688fc931 "accel: introduce accelerator blocker API" aded include/sysemu/accel-blocker.h and accel/accel-blocker.c. MAINTAINERS covers the latter in section "Guest CPU Cores (other accelerators) / Overall", but not the former. Fix that. Signed-off-by: Markus Armbruster Message-Id: <20230119091545.3116376-3-armbru@redhat.com> Reviewed-by: Juan Quintela --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5288eb8271..190a6f5a0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -437,7 +437,7 @@ M: Richard Henderson R: Paolo Bonzini S: Maintained F: include/qemu/accel.h -F: include/sysemu/accel-ops.h +F: include/sysemu/accel-*.h F: include/hw/core/accel-cpu.h F: accel/accel-*.c F: accel/Makefile.objs From ea66c00e7cd79b4cb8aa94a27c5491514dc1662c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 20 Jan 2023 18:01:04 +0100 Subject: [PATCH 387/814] MAINTAINERS: Cover tpm.c again Commit 800d4deda0 "softmmu: move more files to softmmu/" (v5.2.0) updated MAINTAINERS for all moved files but one. Fix that. Fixes: 800d4deda04be016a95fbbf397c830a2d14ff9f6 Signed-off-by: Markus Armbruster Message-Id: <20230120170104.359690-1-armbru@redhat.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 190a6f5a0e..3bd4d101d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3067,7 +3067,7 @@ T: git https://github.com/stefanha/qemu.git tracing TPM M: Stefan Berger S: Maintained -F: tpm.c +F: softmmu/tpm.c F: hw/tpm/* F: include/hw/acpi/tpm.h F: include/sysemu/tpm* From a431ab0e4ef7fcff4349fd8453d0ea5f06ec2617 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 24 Jan 2023 13:20:59 -1000 Subject: [PATCH 388/814] hw/arm: Use TYPE_ARM_SMMUV3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the macro instead of two explicit string literals. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Auger Message-id: 20230124232059.4017615-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- hw/arm/sbsa-ref.c | 3 ++- hw/arm/virt.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 4bb444684f..8378441dbb 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -29,6 +29,7 @@ #include "exec/hwaddr.h" #include "kvm_arm.h" #include "hw/arm/boot.h" +#include "hw/arm/smmuv3.h" #include "hw/block/flash.h" #include "hw/boards.h" #include "hw/ide/internal.h" @@ -574,7 +575,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) DeviceState *dev; int i; - dev = qdev_new("arm-smmuv3"); + dev = qdev_new(TYPE_ARM_SMMUV3); object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ea2413a0ba..90a7099d3b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1343,7 +1343,7 @@ static void create_smmu(const VirtMachineState *vms, return; } - dev = qdev_new("arm-smmuv3"); + dev = qdev_new(TYPE_ARM_SMMUV3); object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); From 9d2617ac7d3139d870ba14204aedd74395990192 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 26 Jan 2023 13:31:34 -1000 Subject: [PATCH 389/814] target/arm: Fix physical address resolution for Stage2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conversion to probe_access_full missed applying the page offset. Cc: qemu-stable@nongnu.org Reported-by: Sid Manning Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230126233134.103193-1-richard.henderson@linaro.org Fixes: f3639a64f602 ("target/arm: Use softmmu tlbs for page table walking") Signed-off-by: Richard Henderson 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 57f3615a66..2b125fff44 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -266,7 +266,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, if (unlikely(flags & TLB_INVALID_MASK)) { goto fail; } - ptw->out_phys = full->phys_addr; + ptw->out_phys = full->phys_addr | (addr & ~TARGET_PAGE_MASK); ptw->out_rw = full->prot & PAGE_WRITE; pte_attrs = full->pte_attrs; pte_secure = full->attrs.secure; From 9d88935cb19f8f8e7291026efe23862316ff2510 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Mon, 23 Jan 2023 17:23:00 +0100 Subject: [PATCH 390/814] hw/char/pl011: refactor FIFO depth handling code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PL011 can be in either of 2 modes depending guest config: FIFO and single register. The last mode could be viewed as a 1-element-deep FIFO. Current code open-codes a bunch of depth-dependent logic. Refactor FIFO depth handling code to isolate calculating current FIFO depth. One functional (albeit guest-invisible) side-effect of this change is that previously we would always increment s->read_pos in UARTDR read handler even if FIFO was disabled, now we are limiting read_pos to not exceed FIFO depth (read_pos itself is reset to 0 if user disables FIFO). Signed-off-by: Evgeny Iakovlev Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230123162304.26254-2-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- hw/char/pl011.c | 30 ++++++++++++++++++------------ include/hw/char/pl011.h | 5 ++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index c076813423..3fa3b75d04 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -81,6 +81,17 @@ static void pl011_update(PL011State *s) } } +static bool pl011_is_fifo_enabled(PL011State *s) +{ + return (s->lcr & 0x10) != 0; +} + +static inline unsigned pl011_get_fifo_depth(PL011State *s) +{ + /* Note: FIFO depth is expected to be power-of-2 */ + return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1; +} + static uint64_t pl011_read(void *opaque, hwaddr offset, unsigned size) { @@ -94,8 +105,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset, c = s->read_fifo[s->read_pos]; if (s->read_count > 0) { s->read_count--; - if (++s->read_pos == 16) - s->read_pos = 0; + s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1); } if (s->read_count == 0) { s->flags |= PL011_FLAG_RXFE; @@ -273,11 +283,7 @@ static int pl011_can_receive(void *opaque) PL011State *s = (PL011State *)opaque; int r; - if (s->lcr & 0x10) { - r = s->read_count < 16; - } else { - r = s->read_count < 1; - } + r = s->read_count < pl011_get_fifo_depth(s); trace_pl011_can_receive(s->lcr, s->read_count, r); return r; } @@ -286,15 +292,15 @@ static void pl011_put_fifo(void *opaque, uint32_t value) { PL011State *s = (PL011State *)opaque; int slot; + unsigned pipe_depth; - slot = s->read_pos + s->read_count; - if (slot >= 16) - slot -= 16; + pipe_depth = pl011_get_fifo_depth(s); + slot = (s->read_pos + s->read_count) & (pipe_depth - 1); s->read_fifo[slot] = value; s->read_count++; s->flags &= ~PL011_FLAG_RXFE; trace_pl011_put_fifo(value, s->read_count); - if (!(s->lcr & 0x10) || s->read_count == 16) { + if (s->read_count == pipe_depth) { trace_pl011_put_fifo_full(); s->flags |= PL011_FLAG_RXFF; } @@ -359,7 +365,7 @@ static const VMStateDescription vmstate_pl011 = { VMSTATE_UINT32(dmacr, PL011State), VMSTATE_UINT32(int_enabled, PL011State), VMSTATE_UINT32(int_level, PL011State), - VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16), + VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH), VMSTATE_UINT32(ilpr, PL011State), VMSTATE_UINT32(ibrd, PL011State), VMSTATE_UINT32(fbrd, PL011State), diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h index dc2c90eedc..926322e242 100644 --- a/include/hw/char/pl011.h +++ b/include/hw/char/pl011.h @@ -27,6 +27,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(PL011State, PL011) /* This shares the same struct (and cast macro) as the base pl011 device */ #define TYPE_PL011_LUMINARY "pl011_luminary" +/* Depth of UART FIFO in bytes, when FIFO mode is enabled (else depth == 1) */ +#define PL011_FIFO_DEPTH 16 + struct PL011State { SysBusDevice parent_obj; @@ -39,7 +42,7 @@ struct PL011State { uint32_t dmacr; uint32_t int_enabled; uint32_t int_level; - uint32_t read_fifo[16]; + uint32_t read_fifo[PL011_FIFO_DEPTH]; uint32_t ilpr; uint32_t ibrd; uint32_t fbrd; From 13ea96fa34bcb6076f42a41194ab363c945e4b07 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Mon, 23 Jan 2023 17:23:01 +0100 Subject: [PATCH 391/814] hw/char/pl011: add post_load hook for backwards-compatibility Previous change slightly modified the way we handle data writes when FIFO is disabled. Previously we kept incrementing read_pos and were storing data at that position, although we only have a single-register-deep FIFO now. Then we changed it to always store data at pos 0. If guest disables FIFO and the proceeds to read data, it will work out fine, because we still read from current read_pos before setting it to 0. However, to make code less fragile, introduce a post_load hook for PL011State and move fixup read FIFO state when FIFO is disabled. Since we are introducing a post_load hook, also do some sanity checking on untrusted incoming input state. Signed-off-by: Evgeny Iakovlev Message-id: 20230123162304.26254-3-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- hw/char/pl011.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 3fa3b75d04..05e8bdc050 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -352,10 +352,35 @@ static const VMStateDescription vmstate_pl011_clock = { } }; +static int pl011_post_load(void *opaque, int version_id) +{ + PL011State* s = opaque; + + /* Sanity-check input state */ + if (s->read_pos >= ARRAY_SIZE(s->read_fifo) || + s->read_count > ARRAY_SIZE(s->read_fifo)) { + return -1; + } + + if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) { + /* + * Older versions of PL011 didn't ensure that the single + * character in the FIFO in FIFO-disabled mode is in + * element 0 of the array; convert to follow the current + * code's assumptions. + */ + s->read_fifo[0] = s->read_fifo[s->read_pos]; + s->read_pos = 0; + } + + return 0; +} + static const VMStateDescription vmstate_pl011 = { .name = "pl011", .version_id = 2, .minimum_version_id = 2, + .post_load = pl011_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(readbuff, PL011State), VMSTATE_UINT32(flags, PL011State), From 3b7a165e8c94b1f7eee326fa6b68eb45f0324ea1 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Mon, 23 Jan 2023 17:23:02 +0100 Subject: [PATCH 392/814] hw/char/pl011: implement a reset method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PL011 currently lacks a reset method. Implement it. Signed-off-by: Evgeny Iakovlev Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230123162304.26254-4-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- hw/char/pl011.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 05e8bdc050..ca7537d8ed 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -427,11 +427,6 @@ static void pl011_init(Object *obj) s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s, ClockUpdate); - s->read_trigger = 1; - s->ifl = 0x12; - s->cr = 0x300; - s->flags = 0x90; - s->id = pl011_id_arm; } @@ -443,11 +438,32 @@ static void pl011_realize(DeviceState *dev, Error **errp) pl011_event, NULL, s, NULL, true); } +static void pl011_reset(DeviceState *dev) +{ + PL011State *s = PL011(dev); + + s->lcr = 0; + s->rsr = 0; + s->dmacr = 0; + s->int_enabled = 0; + s->int_level = 0; + s->ilpr = 0; + s->ibrd = 0; + s->fbrd = 0; + s->read_pos = 0; + s->read_count = 0; + s->read_trigger = 1; + s->ifl = 0x12; + s->cr = 0x300; + s->flags = 0x90; +} + static void pl011_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = pl011_realize; + dc->reset = pl011_reset; dc->vmsd = &vmstate_pl011; device_class_set_props(dc, pl011_properties); } From 23dcbfc080eb8a8e8395d753f07adbb0ab761143 Mon Sep 17 00:00:00 2001 From: Evgeny Iakovlev Date: Mon, 23 Jan 2023 17:23:03 +0100 Subject: [PATCH 393/814] hw/char/pl011: better handling of FIFO flags on LCR reset Current FIFO handling code does not reset RXFE/RXFF flags when guest resets FIFO by writing to UARTLCR register, although internal FIFO state is reset to 0 read count. Actual guest-visible flag update will happen only on next data read or write attempt. As a result of that any guest that expects RXFE flag to be set (and RXFF to be cleared) after resetting FIFO will never see that happen. Signed-off-by: Evgeny Iakovlev Reviewed-by: Peter Maydell Message-id: 20230123162304.26254-5-eiakovlev@linux.microsoft.com Signed-off-by: Peter Maydell --- hw/char/pl011.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/char/pl011.c b/hw/char/pl011.c index ca7537d8ed..c15cb7af20 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -92,6 +92,16 @@ static inline unsigned pl011_get_fifo_depth(PL011State *s) return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1; } +static inline void pl011_reset_fifo(PL011State *s) +{ + s->read_count = 0; + s->read_pos = 0; + + /* Reset FIFO flags */ + s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF); + s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE; +} + static uint64_t pl011_read(void *opaque, hwaddr offset, unsigned size) { @@ -239,8 +249,7 @@ static void pl011_write(void *opaque, hwaddr offset, case 11: /* UARTLCR_H */ /* Reset the FIFO state on FIFO enable or disable */ if ((s->lcr ^ value) & 0x10) { - s->read_count = 0; - s->read_pos = 0; + pl011_reset_fifo(s); } if ((s->lcr ^ value) & 0x1) { int break_enable = value & 0x1; @@ -450,12 +459,11 @@ static void pl011_reset(DeviceState *dev) s->ilpr = 0; s->ibrd = 0; s->fbrd = 0; - s->read_pos = 0; - s->read_count = 0; s->read_trigger = 1; s->ifl = 0x12; s->cr = 0x300; - s->flags = 0x90; + s->flags = 0; + pl011_reset_fifo(s); } static void pl011_class_init(ObjectClass *oc, void *data) From a2260983c65539010310b7105da284026cfceba4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 28 Jan 2023 23:44:59 +0100 Subject: [PATCH 394/814] hvf: arm: Add support for GICv3 We currently only support GICv2 emulation. To also support GICv3, we will need to pass a few system registers into their respective handler functions. This patch adds support for HVF to call into the TCG callbacks for GICv3 system register handlers. This is safe because the GICv3 TCG code is generic as long as we limit ourselves to EL0 and EL1 - which are the only modes supported by HVF. To make sure nobody trips over that, we also annotate callbacks that don't work in HVF mode, such as EL state change hooks. With GICv3 support in place, we can run with more than 8 vCPUs. Signed-off-by: Alexander Graf Message-id: 20230128224459.70676-1-agraf@csgraf.de Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_cpuif.c | 16 +++- target/arm/hvf/hvf.c | 151 ++++++++++++++++++++++++++++++++++++ target/arm/hvf/trace-events | 2 + 3 files changed, 168 insertions(+), 1 deletion(-) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index b17b29288c..9a7fc19099 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -21,6 +21,8 @@ #include "hw/irq.h" #include "cpu.h" #include "target/arm/cpregs.h" +#include "sysemu/tcg.h" +#include "sysemu/qtest.h" /* * Special case return value from hppvi_index(); must be larger than @@ -2810,6 +2812,8 @@ void gicv3_init_cpuif(GICv3State *s) * which case we'd get the wrong value. * So instead we define the regs with no ri->opaque info, and * get back to the GICv3CPUState from the CPUARMState. + * + * These CP regs callbacks can be called from either TCG or HVF code. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); @@ -2905,6 +2909,16 @@ void gicv3_init_cpuif(GICv3State *s) define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); } } - arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + if (tcg_enabled() || qtest_enabled()) { + /* + * We can only trap EL changes with TCG. However the GIC interrupt + * state only changes on EL changes involving EL2 or EL3, so for + * the non-TCG case this is OK, as EL2 and EL3 can't exist. + */ + arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } else { + assert(!arm_feature(&cpu->env, ARM_FEATURE_EL2)); + assert(!arm_feature(&cpu->env, ARM_FEATURE_EL3)); + } } } diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 060aa0ccf4..ad65603445 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -80,6 +80,33 @@ #define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 9, 13, 0) #define SYSREG_PMCCFILTR_EL0 SYSREG(3, 3, 14, 15, 7) +#define SYSREG_ICC_AP0R0_EL1 SYSREG(3, 0, 12, 8, 4) +#define SYSREG_ICC_AP0R1_EL1 SYSREG(3, 0, 12, 8, 5) +#define SYSREG_ICC_AP0R2_EL1 SYSREG(3, 0, 12, 8, 6) +#define SYSREG_ICC_AP0R3_EL1 SYSREG(3, 0, 12, 8, 7) +#define SYSREG_ICC_AP1R0_EL1 SYSREG(3, 0, 12, 9, 0) +#define SYSREG_ICC_AP1R1_EL1 SYSREG(3, 0, 12, 9, 1) +#define SYSREG_ICC_AP1R2_EL1 SYSREG(3, 0, 12, 9, 2) +#define SYSREG_ICC_AP1R3_EL1 SYSREG(3, 0, 12, 9, 3) +#define SYSREG_ICC_ASGI1R_EL1 SYSREG(3, 0, 12, 11, 6) +#define SYSREG_ICC_BPR0_EL1 SYSREG(3, 0, 12, 8, 3) +#define SYSREG_ICC_BPR1_EL1 SYSREG(3, 0, 12, 12, 3) +#define SYSREG_ICC_CTLR_EL1 SYSREG(3, 0, 12, 12, 4) +#define SYSREG_ICC_DIR_EL1 SYSREG(3, 0, 12, 11, 1) +#define SYSREG_ICC_EOIR0_EL1 SYSREG(3, 0, 12, 8, 1) +#define SYSREG_ICC_EOIR1_EL1 SYSREG(3, 0, 12, 12, 1) +#define SYSREG_ICC_HPPIR0_EL1 SYSREG(3, 0, 12, 8, 2) +#define SYSREG_ICC_HPPIR1_EL1 SYSREG(3, 0, 12, 12, 2) +#define SYSREG_ICC_IAR0_EL1 SYSREG(3, 0, 12, 8, 0) +#define SYSREG_ICC_IAR1_EL1 SYSREG(3, 0, 12, 12, 0) +#define SYSREG_ICC_IGRPEN0_EL1 SYSREG(3, 0, 12, 12, 6) +#define SYSREG_ICC_IGRPEN1_EL1 SYSREG(3, 0, 12, 12, 7) +#define SYSREG_ICC_PMR_EL1 SYSREG(3, 0, 4, 6, 0) +#define SYSREG_ICC_RPR_EL1 SYSREG(3, 0, 12, 11, 3) +#define SYSREG_ICC_SGI0R_EL1 SYSREG(3, 0, 12, 11, 7) +#define SYSREG_ICC_SGI1R_EL1 SYSREG(3, 0, 12, 11, 5) +#define SYSREG_ICC_SRE_EL1 SYSREG(3, 0, 12, 12, 5) + #define WFX_IS_WFE (1 << 0) #define TMR_CTL_ENABLE (1 << 0) @@ -788,6 +815,43 @@ static bool is_id_sysreg(uint32_t reg) SYSREG_CRM(reg) < 8; } +static uint32_t hvf_reg2cp_reg(uint32_t reg) +{ + return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, + (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK, + (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK, + (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK, + (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK, + (reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK); +} + +static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val) +{ + ARMCPU *arm_cpu = ARM_CPU(cpu); + CPUARMState *env = &arm_cpu->env; + const ARMCPRegInfo *ri; + + ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg)); + if (ri) { + if (ri->accessfn) { + if (ri->accessfn(env, ri, true) != CP_ACCESS_OK) { + return false; + } + } + if (ri->type & ARM_CP_CONST) { + *val = ri->resetvalue; + } else if (ri->readfn) { + *val = ri->readfn(env, ri); + } else { + *val = CPREG_FIELD64(env, ri); + } + trace_hvf_vgic_read(ri->name, *val); + return true; + } + + return false; +} + static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) { ARMCPU *arm_cpu = ARM_CPU(cpu); @@ -839,6 +903,36 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_OSDLR_EL1: /* Dummy register */ break; + case SYSREG_ICC_AP0R0_EL1: + case SYSREG_ICC_AP0R1_EL1: + case SYSREG_ICC_AP0R2_EL1: + case SYSREG_ICC_AP0R3_EL1: + case SYSREG_ICC_AP1R0_EL1: + case SYSREG_ICC_AP1R1_EL1: + case SYSREG_ICC_AP1R2_EL1: + case SYSREG_ICC_AP1R3_EL1: + case SYSREG_ICC_ASGI1R_EL1: + case SYSREG_ICC_BPR0_EL1: + case SYSREG_ICC_BPR1_EL1: + case SYSREG_ICC_DIR_EL1: + case SYSREG_ICC_EOIR0_EL1: + case SYSREG_ICC_EOIR1_EL1: + case SYSREG_ICC_HPPIR0_EL1: + case SYSREG_ICC_HPPIR1_EL1: + case SYSREG_ICC_IAR0_EL1: + case SYSREG_ICC_IAR1_EL1: + case SYSREG_ICC_IGRPEN0_EL1: + case SYSREG_ICC_IGRPEN1_EL1: + case SYSREG_ICC_PMR_EL1: + case SYSREG_ICC_SGI0R_EL1: + case SYSREG_ICC_SGI1R_EL1: + case SYSREG_ICC_SRE_EL1: + case SYSREG_ICC_CTLR_EL1: + /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ + if (!hvf_sysreg_read_cp(cpu, reg, &val)) { + hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); + } + break; default: if (is_id_sysreg(reg)) { /* ID system registers read as RES0 */ @@ -944,6 +1038,33 @@ static void pmswinc_write(CPUARMState *env, uint64_t value) } } +static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val) +{ + ARMCPU *arm_cpu = ARM_CPU(cpu); + CPUARMState *env = &arm_cpu->env; + const ARMCPRegInfo *ri; + + ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_reg2cp_reg(reg)); + + if (ri) { + if (ri->accessfn) { + if (ri->accessfn(env, ri, false) != CP_ACCESS_OK) { + return false; + } + } + if (ri->writefn) { + ri->writefn(env, ri, val); + } else { + CPREG_FIELD64(env, ri) = val; + } + + trace_hvf_vgic_write(ri->name, val); + return true; + } + + return false; +} + static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) { ARMCPU *arm_cpu = ARM_CPU(cpu); @@ -1021,6 +1142,36 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_OSDLR_EL1: /* Dummy register */ break; + case SYSREG_ICC_AP0R0_EL1: + case SYSREG_ICC_AP0R1_EL1: + case SYSREG_ICC_AP0R2_EL1: + case SYSREG_ICC_AP0R3_EL1: + case SYSREG_ICC_AP1R0_EL1: + case SYSREG_ICC_AP1R1_EL1: + case SYSREG_ICC_AP1R2_EL1: + case SYSREG_ICC_AP1R3_EL1: + case SYSREG_ICC_ASGI1R_EL1: + case SYSREG_ICC_BPR0_EL1: + case SYSREG_ICC_BPR1_EL1: + case SYSREG_ICC_CTLR_EL1: + case SYSREG_ICC_DIR_EL1: + case SYSREG_ICC_EOIR0_EL1: + case SYSREG_ICC_EOIR1_EL1: + case SYSREG_ICC_HPPIR0_EL1: + case SYSREG_ICC_HPPIR1_EL1: + case SYSREG_ICC_IAR0_EL1: + case SYSREG_ICC_IAR1_EL1: + case SYSREG_ICC_IGRPEN0_EL1: + case SYSREG_ICC_IGRPEN1_EL1: + case SYSREG_ICC_PMR_EL1: + case SYSREG_ICC_SGI0R_EL1: + case SYSREG_ICC_SGI1R_EL1: + case SYSREG_ICC_SRE_EL1: + /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ + if (!hvf_sysreg_write_cp(cpu, reg, val)) { + hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); + } + break; default: cpu_synchronize_state(cpu); trace_hvf_unhandled_sysreg_write(env->pc, reg, diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events index 820e8e0297..4fbbe4b45e 100644 --- a/target/arm/hvf/trace-events +++ b/target/arm/hvf/trace-events @@ -9,3 +9,5 @@ hvf_unknown_hvc(uint64_t x0) "unknown HVC! 0x%016"PRIx64 hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64 hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]" hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpu=0x%x" +hvf_vgic_write(const char *name, uint64_t val) "vgic write to %s [val=0x%016"PRIx64"]" +hvf_vgic_read(const char *name, uint64_t val) "vgic read from %s [val=0x%016"PRIx64"]" From a3495d11c4970c6cac05da516439a4f74ff6db01 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 23 Dec 2022 10:01:06 +0100 Subject: [PATCH 395/814] hw/arm/virt: Consolidate GIC finalize logic Up to now, the finalize_gic_version() code open coded what is essentially a support bitmap match between host/emulation environment and desired target GIC type. This open coding leads to undesirable side effects. For example, a VM with KVM and -smp 10 will automatically choose GICv3 while the same command line with TCG will stay on GICv2 and fail the launch. This patch combines the TCG and KVM matching code paths by making everything a 2 pass process. First, we determine which GIC versions the current environment is able to support, then we go through a single state machine to determine which target GIC mode that means for us. After this patch, the only user noticable changes should be consolidated error messages as well as TCG -M virt supporting -smp > 8 automatically. Signed-off-by: Alexander Graf Reviewed-by: Richard Henderson Reviewed-by: Cornelia Huck Reviewed-by: Zenghui Yu Message-id: 20221223090107.98888-2-agraf@csgraf.de Signed-off-by: Peter Maydell --- hw/arm/virt.c | 198 ++++++++++++++++++++++-------------------- include/hw/arm/virt.h | 15 ++-- 2 files changed, 112 insertions(+), 101 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 90a7099d3b..28c43d59fb 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1820,6 +1820,84 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) } } +static VirtGICType finalize_gic_version_do(const char *accel_name, + VirtGICType gic_version, + int gics_supported, + unsigned int max_cpus) +{ + /* Convert host/max/nosel to GIC version number */ + switch (gic_version) { + case VIRT_GIC_VERSION_HOST: + if (!kvm_enabled()) { + error_report("gic-version=host requires KVM"); + exit(1); + } + + /* For KVM, gic-version=host means gic-version=max */ + return finalize_gic_version_do(accel_name, VIRT_GIC_VERSION_MAX, + gics_supported, max_cpus); + case VIRT_GIC_VERSION_MAX: + if (gics_supported & VIRT_GIC_VERSION_4_MASK) { + gic_version = VIRT_GIC_VERSION_4; + } else if (gics_supported & VIRT_GIC_VERSION_3_MASK) { + gic_version = VIRT_GIC_VERSION_3; + } else { + gic_version = VIRT_GIC_VERSION_2; + } + break; + case VIRT_GIC_VERSION_NOSEL: + if ((gics_supported & VIRT_GIC_VERSION_2_MASK) && + max_cpus <= GIC_NCPU) { + gic_version = VIRT_GIC_VERSION_2; + } else if (gics_supported & VIRT_GIC_VERSION_3_MASK) { + /* + * in case the host does not support v2 emulation or + * the end-user requested more than 8 VCPUs we now default + * to v3. In any case defaulting to v2 would be broken. + */ + gic_version = VIRT_GIC_VERSION_3; + } else if (max_cpus > GIC_NCPU) { + error_report("%s only supports GICv2 emulation but more than 8 " + "vcpus are requested", accel_name); + exit(1); + } + break; + case VIRT_GIC_VERSION_2: + case VIRT_GIC_VERSION_3: + case VIRT_GIC_VERSION_4: + break; + } + + /* Check chosen version is effectively supported */ + switch (gic_version) { + case VIRT_GIC_VERSION_2: + if (!(gics_supported & VIRT_GIC_VERSION_2_MASK)) { + error_report("%s does not support GICv2 emulation", accel_name); + exit(1); + } + break; + case VIRT_GIC_VERSION_3: + if (!(gics_supported & VIRT_GIC_VERSION_3_MASK)) { + error_report("%s does not support GICv3 emulation", accel_name); + exit(1); + } + break; + case VIRT_GIC_VERSION_4: + if (!(gics_supported & VIRT_GIC_VERSION_4_MASK)) { + error_report("%s does not support GICv4 emulation, is virtualization=on?", + accel_name); + exit(1); + } + break; + default: + error_report("logic error in finalize_gic_version"); + exit(1); + break; + } + + return gic_version; +} + /* * finalize_gic_version - Determines the final gic_version * according to the gic-version property @@ -1828,118 +1906,46 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) */ static void finalize_gic_version(VirtMachineState *vms) { + const char *accel_name = current_accel_name(); unsigned int max_cpus = MACHINE(vms)->smp.max_cpus; + int gics_supported = 0; - if (kvm_enabled()) { - int probe_bitmap; + /* Determine which GIC versions the current environment supports */ + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + int probe_bitmap = kvm_arm_vgic_probe(); - if (!kvm_irqchip_in_kernel()) { - switch (vms->gic_version) { - case VIRT_GIC_VERSION_HOST: - warn_report( - "gic-version=host not relevant with kernel-irqchip=off " - "as only userspace GICv2 is supported. Using v2 ..."); - return; - case VIRT_GIC_VERSION_MAX: - case VIRT_GIC_VERSION_NOSEL: - vms->gic_version = VIRT_GIC_VERSION_2; - return; - case VIRT_GIC_VERSION_2: - return; - case VIRT_GIC_VERSION_3: - error_report( - "gic-version=3 is not supported with kernel-irqchip=off"); - exit(1); - case VIRT_GIC_VERSION_4: - error_report( - "gic-version=4 is not supported with kernel-irqchip=off"); - exit(1); - } - } - - probe_bitmap = kvm_arm_vgic_probe(); if (!probe_bitmap) { error_report("Unable to determine GIC version supported by host"); exit(1); } - switch (vms->gic_version) { - case VIRT_GIC_VERSION_HOST: - case VIRT_GIC_VERSION_MAX: - if (probe_bitmap & KVM_ARM_VGIC_V3) { - vms->gic_version = VIRT_GIC_VERSION_3; - } else { - vms->gic_version = VIRT_GIC_VERSION_2; - } - return; - case VIRT_GIC_VERSION_NOSEL: - if ((probe_bitmap & KVM_ARM_VGIC_V2) && max_cpus <= GIC_NCPU) { - vms->gic_version = VIRT_GIC_VERSION_2; - } else if (probe_bitmap & KVM_ARM_VGIC_V3) { - /* - * in case the host does not support v2 in-kernel emulation or - * the end-user requested more than 8 VCPUs we now default - * to v3. In any case defaulting to v2 would be broken. - */ - vms->gic_version = VIRT_GIC_VERSION_3; - } else if (max_cpus > GIC_NCPU) { - error_report("host only supports in-kernel GICv2 emulation " - "but more than 8 vcpus are requested"); - exit(1); - } - break; - case VIRT_GIC_VERSION_2: - case VIRT_GIC_VERSION_3: - break; - case VIRT_GIC_VERSION_4: - error_report("gic-version=4 is not supported with KVM"); - exit(1); + if (probe_bitmap & KVM_ARM_VGIC_V2) { + gics_supported |= VIRT_GIC_VERSION_2_MASK; } - - /* Check chosen version is effectively supported by the host */ - if (vms->gic_version == VIRT_GIC_VERSION_2 && - !(probe_bitmap & KVM_ARM_VGIC_V2)) { - error_report("host does not support in-kernel GICv2 emulation"); - exit(1); - } else if (vms->gic_version == VIRT_GIC_VERSION_3 && - !(probe_bitmap & KVM_ARM_VGIC_V3)) { - error_report("host does not support in-kernel GICv3 emulation"); - exit(1); + if (probe_bitmap & KVM_ARM_VGIC_V3) { + gics_supported |= VIRT_GIC_VERSION_3_MASK; } - return; - } - - /* TCG mode */ - switch (vms->gic_version) { - case VIRT_GIC_VERSION_NOSEL: - vms->gic_version = VIRT_GIC_VERSION_2; - break; - case VIRT_GIC_VERSION_MAX: + } else if (kvm_enabled() && !kvm_irqchip_in_kernel()) { + /* KVM w/o kernel irqchip can only deal with GICv2 */ + gics_supported |= VIRT_GIC_VERSION_2_MASK; + accel_name = "KVM with kernel-irqchip=off"; + } else { + gics_supported |= VIRT_GIC_VERSION_2_MASK; if (module_object_class_by_name("arm-gicv3")) { - /* CONFIG_ARM_GICV3_TCG was set */ + gics_supported |= VIRT_GIC_VERSION_3_MASK; if (vms->virt) { /* GICv4 only makes sense if CPU has EL2 */ - vms->gic_version = VIRT_GIC_VERSION_4; - } else { - vms->gic_version = VIRT_GIC_VERSION_3; + gics_supported |= VIRT_GIC_VERSION_4_MASK; } - } else { - vms->gic_version = VIRT_GIC_VERSION_2; } - break; - case VIRT_GIC_VERSION_HOST: - error_report("gic-version=host requires KVM"); - exit(1); - case VIRT_GIC_VERSION_4: - if (!vms->virt) { - error_report("gic-version=4 requires virtualization enabled"); - exit(1); - } - break; - case VIRT_GIC_VERSION_2: - case VIRT_GIC_VERSION_3: - break; } + + /* + * Then convert helpers like host/max to concrete GIC versions and ensure + * the desired version is supported + */ + vms->gic_version = finalize_gic_version_do(accel_name, vms->gic_version, + gics_supported, max_cpus); } /* diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index c7dd59d7f1..e1ddbea96b 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -109,14 +109,19 @@ typedef enum VirtMSIControllerType { } VirtMSIControllerType; typedef enum VirtGICType { - VIRT_GIC_VERSION_MAX, - VIRT_GIC_VERSION_HOST, - VIRT_GIC_VERSION_2, - VIRT_GIC_VERSION_3, - VIRT_GIC_VERSION_4, + VIRT_GIC_VERSION_MAX = 0, + VIRT_GIC_VERSION_HOST = 1, + /* The concrete GIC values have to match the GIC version number */ + VIRT_GIC_VERSION_2 = 2, + VIRT_GIC_VERSION_3 = 3, + VIRT_GIC_VERSION_4 = 4, VIRT_GIC_VERSION_NOSEL, } VirtGICType; +#define VIRT_GIC_VERSION_2_MASK BIT(VIRT_GIC_VERSION_2) +#define VIRT_GIC_VERSION_3_MASK BIT(VIRT_GIC_VERSION_3) +#define VIRT_GIC_VERSION_4_MASK BIT(VIRT_GIC_VERSION_4) + struct VirtMachineClass { MachineClass parent; bool disallow_affinity_adjustment; From 5e91b9e03f6cbb0f8333e60422ef44c15b4775c7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 23 Dec 2022 10:01:07 +0100 Subject: [PATCH 396/814] hw/arm/virt: Make accels in GIC finalize logic explicit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's explicitly list out all accelerators that we support when trying to determine the supported set of GIC versions. KVM was already separate, so the only missing one is HVF which simply reuses all of TCG's emulation code and thus has the same compatibility matrix. Signed-off-by: Alexander Graf Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cornelia Huck Reviewed-by: Zenghui Yu Reviewed-by: Richard Henderson Message-id: 20221223090107.98888-3-agraf@csgraf.de [PMM: Added qtest to the list of accelerators] Signed-off-by: Peter Maydell --- hw/arm/virt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 28c43d59fb..ba47728288 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -47,8 +47,10 @@ #include "sysemu/numa.h" #include "sysemu/runstate.h" #include "sysemu/tpm.h" +#include "sysemu/tcg.h" #include "sysemu/kvm.h" #include "sysemu/hvf.h" +#include "sysemu/qtest.h" #include "hw/loader.h" #include "qapi/error.h" #include "qemu/bitops.h" @@ -1929,7 +1931,7 @@ static void finalize_gic_version(VirtMachineState *vms) /* KVM w/o kernel irqchip can only deal with GICv2 */ gics_supported |= VIRT_GIC_VERSION_2_MASK; accel_name = "KVM with kernel-irqchip=off"; - } else { + } else if (tcg_enabled() || hvf_enabled() || qtest_enabled()) { gics_supported |= VIRT_GIC_VERSION_2_MASK; if (module_object_class_by_name("arm-gicv3")) { gics_supported |= VIRT_GIC_VERSION_3_MASK; @@ -1938,6 +1940,9 @@ static void finalize_gic_version(VirtMachineState *vms) gics_supported |= VIRT_GIC_VERSION_4_MASK; } } + } else { + error_report("Unsupported accelerator, can not determine GIC support"); + exit(1); } /* From ed65e32cf52a91c620c925faa90049b8e35365e1 Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Thu, 26 Jan 2023 12:44:16 +0100 Subject: [PATCH 397/814] sbsa-ref: remove cortex-a76 from list of supported cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cortex-A76 supports 40bits of address space. sbsa-ref's memory starts above this limit. Signed-off-by: Marcin Juszkiewicz Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-id: 20230126114416.2447685-1-marcin.juszkiewicz@linaro.org Signed-off-by: Peter Maydell --- hw/arm/sbsa-ref.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 8378441dbb..f778cb6d09 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -146,7 +146,6 @@ static const int sbsa_ref_irqmap[] = { static const char * const valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), - ARM_CPU_TYPE_NAME("cortex-a76"), ARM_CPU_TYPE_NAME("neoverse-n1"), ARM_CPU_TYPE_NAME("max"), }; From 3999d2d290a5c722c15bac9272e47090a95a0554 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:37 +0000 Subject: [PATCH 398/814] target/arm: Name AT_S1E1RP and AT_S1E1WP cpregs correctly The encodings 0,0,C7,C9,0 and 0,0,C7,C9,1 are AT SP1E1RP and AT S1E1WP, but our ARMCPRegInfo definitions for them incorrectly name them AT S1E1R and AT S1E1W (which are entirely different instructions). Fix the names. (This has no guest-visible effect as the names are for debug purposes only.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-2-peter.maydell@linaro.org Message-id: 20230127175507.2895013-2-peter.maydell@linaro.org --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 72b37b7cf1..ccb7d1e171 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7734,11 +7734,11 @@ static const ARMCPRegInfo vhe_reginfo[] = { #ifndef CONFIG_USER_ONLY static const ARMCPRegInfo ats1e1_reginfo[] = { - { .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64, + { .name = "AT_S1E1RP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, - { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64, + { .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 }, From ce9a8863b2c465a7227984bdadf743786f7a1849 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:38 +0000 Subject: [PATCH 399/814] target/arm: Correct syndrome for ATS12NSO* at Secure EL1 The AArch32 ATS12NSO* address translation operations are supposed to trap to either EL2 or EL3 if they're executed at Secure EL1 (which can only happen if EL3 is AArch64). We implement this, but we got the syndrome value wrong: like other traps to EL2 or EL3 on an AArch32 cpreg access, they should report the 0x3 syndrome, not the 0x0 'uncategorized' syndrome. This is clear in the access pseudocode for these instructions. Fix the syndrome value for these operations by correcting the returned value from the ats_access() function. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-3-peter.maydell@linaro.org Message-id: 20230127175507.2895013-3-peter.maydell@linaro.org --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index ccb7d1e171..6f6772d8e0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3284,9 +3284,9 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_current_el(env) == 1) { if (arm_is_secure_below_el3(env)) { if (env->cp15.scr_el3 & SCR_EEL2) { - return CP_ACCESS_TRAP_UNCATEGORIZED_EL2; + return CP_ACCESS_TRAP_EL2; } - return CP_ACCESS_TRAP_UNCATEGORIZED_EL3; + return CP_ACCESS_TRAP_EL3; } return CP_ACCESS_TRAP_UNCATEGORIZED; } From 80ea70f2e53469b468598508513d50c5f80d6bb9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:39 +0000 Subject: [PATCH 400/814] target/arm: Remove CP_ACCESS_TRAP_UNCATEGORIZED_{EL2, EL3} We added the CPAccessResult values CP_ACCESS_TRAP_UNCATEGORIZED_EL2 and CP_ACCESS_TRAP_UNCATEGORIZED_EL3 purely in order to use them in the ats_access() function, but doing so was incorrect (a bug fixed in a previous commit). There aren't any cases where we want an access function to be able to request a trap to EL2 or EL3 with a zero syndrome value, so remove these enum values. As well as cleaning up dead code, the motivation here is that we'd like to implement fine-grained-trap handling in helper_access_check_cp_reg(). Although the fine-grained traps to EL2 are always lower priority than trap-to-same-EL and higher priority than trap-to-EL3, they are in the middle of various other kinds of trap-to-EL2. Knowing that a trap-to-EL2 must always for us have the same syndrome (ie that an access function will return CP_ACCESS_TRAP_EL2 and there is no other kind of trap-to-EL2 enum value) means we don't have to try to choose which of the two syndrome values to report if the access would trap to EL2 both for the fine-grained-trap and because the access function requires it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-4-peter.maydell@linaro.org Message-id: 20230127175507.2895013-4-peter.maydell@linaro.org --- target/arm/cpregs.h | 4 ++-- target/arm/op_helper.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 7e78c2c05c..9744179df0 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -224,10 +224,10 @@ typedef enum CPAccessResult { * Access fails and results in an exception syndrome 0x0 ("uncategorized"). * Note that this is not a catch-all case -- the set of cases which may * result in this failure is specifically defined by the architecture. + * This trap is always to the usual target EL, never directly to a + * specified target EL. */ CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2), - CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2, - CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3, } CPAccessResult; typedef struct ARMCPRegInfo ARMCPRegInfo; diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 31f89db899..def5d3515e 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -673,6 +673,8 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, case CP_ACCESS_TRAP: break; case CP_ACCESS_TRAP_UNCATEGORIZED: + /* Only CP_ACCESS_TRAP traps are direct to a specified EL */ + assert((res & CP_ACCESS_EL_MASK) == 0); if (cpu_isar_feature(aa64_ids, cpu) && isread && arm_cpreg_in_idspace(ri)) { /* From 9ada333982c3d5ae4c15b8ba8dcfd7cb6cd6cb44 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:40 +0000 Subject: [PATCH 401/814] target/arm: Move do_coproc_insn() syndrome calculation earlier Rearrange the code in do_coproc_insn() so that we calculate the syndrome value for a potential trap early; we're about to add a second check that wants this value earlier than where it is currently determined. (Specifically, a trap to EL2 because of HSTR_EL2 should take priority over an UNDEF to EL1, even when the UNDEF is because the register does not exist at all or because its ri->access bits non-configurably fail the access. So the check we put in for HSTR_EL2 trapping at EL1 (which needs the syndrome) is going to have to be done before the check "is the ARMCPRegInfo pointer NULL".) This commit is just code motion; the change to HSTR_EL2 handling that will use the 'syndrome' variable is in a subsequent commit. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-5-peter.maydell@linaro.org Message-id: 20230127175507.2895013-5-peter.maydell@linaro.org --- target/arm/translate.c | 83 +++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 365e02fb0b..9252a464a1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4718,6 +4718,47 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); TCGv_ptr tcg_ri = NULL; bool need_exit_tb; + uint32_t syndrome; + + /* + * Note that since we are an implementation which takes an + * exception on a trapped conditional instruction only if the + * instruction passes its condition code check, we can take + * advantage of the clause in the ARM ARM that allows us to set + * the COND field in the instruction to 0xE in all cases. + * We could fish the actual condition out of the insn (ARM) + * or the condexec bits (Thumb) but it isn't necessary. + */ + switch (cpnum) { + case 14: + if (is64) { + syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2, + isread, false); + } else { + syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm, + rt, isread, false); + } + break; + case 15: + if (is64) { + syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2, + isread, false); + } else { + syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm, + rt, isread, false); + } + break; + default: + /* + * ARMv8 defines that only coprocessors 14 and 15 exist, + * so this can only happen if this is an ARMv7 or earlier CPU, + * in which case the syndrome information won't actually be + * guest visible. + */ + assert(!arm_dc_feature(s, ARM_FEATURE_V8)); + syndrome = syn_uncategorized(); + break; + } if (!ri) { /* @@ -4755,48 +4796,6 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, * Note that on XScale all cp0..c13 registers do an access check * call in order to handle c15_cpar. */ - uint32_t syndrome; - - /* - * Note that since we are an implementation which takes an - * exception on a trapped conditional instruction only if the - * instruction passes its condition code check, we can take - * advantage of the clause in the ARM ARM that allows us to set - * the COND field in the instruction to 0xE in all cases. - * We could fish the actual condition out of the insn (ARM) - * or the condexec bits (Thumb) but it isn't necessary. - */ - switch (cpnum) { - case 14: - if (is64) { - syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, false); - } else { - syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, false); - } - break; - case 15: - if (is64) { - syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, false); - } else { - syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, false); - } - break; - default: - /* - * ARMv8 defines that only coprocessors 14 and 15 exist, - * so this can only happen if this is an ARMv7 or earlier CPU, - * in which case the syndrome information won't actually be - * guest visible. - */ - assert(!arm_dc_feature(s, ARM_FEATURE_V8)); - syndrome = syn_uncategorized(); - break; - } - gen_set_condexec(s); gen_update_pc(s, 0); tcg_ri = tcg_temp_new_ptr(); From cccc104bbfc02c741d4535be0184a6425399345d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:41 +0000 Subject: [PATCH 402/814] target/arm: All UNDEF-at-EL0 traps take priority over HSTR_EL2 traps The HSTR_EL2 register has a collection of trap bits which allow trapping to EL2 for AArch32 EL0 or EL1 accesses to coprocessor registers. The specification of these bits is that when the bit is set we should trap * EL1 accesses * EL0 accesses, if the access is not UNDEFINED when the trap bit is 0 In other words, all UNDEF traps from EL0 to EL1 take precedence over the HSTR_EL2 trap to EL2. (Since this is all AArch32, the only kind of trap-to-EL1 is the UNDEF.) Our implementation doesn't quite get this right -- we check for traps in the order: * no such register * ARMCPRegInfo::access bits * HSTR_EL2 trap bits * ARMCPRegInfo::accessfn So UNDEFs that happen because of the access bits or because the register doesn't exist at all correctly take priority over the HSTR_EL2 trap, but where a register can UNDEF at EL0 because of the accessfn we are incorrectly always taking the HSTR_EL2 trap. There aren't many of these, but one example is the PMCR; if you look at the access pseudocode for this register you can see that UNDEFs taken because of the value of PMUSERENR.EN are checked before the HSTR_EL2 bit. Rearrange helper_access_check_cp_reg() so that we always call the accessfn, and use its return value if it indicates that the access traps to EL0 rather than continuing to do the HSTR_EL2 check. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-6-peter.maydell@linaro.org Message-id: 20230127175507.2895013-6-peter.maydell@linaro.org --- target/arm/op_helper.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index def5d3515e..660dae696d 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -640,10 +640,24 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, goto fail; } + if (ri->accessfn) { + res = ri->accessfn(env, ri, isread); + } + /* - * Check for an EL2 trap due to HSTR_EL2. We expect EL0 accesses - * to sysregs non accessible at EL0 to have UNDEF-ed already. + * If the access function indicates a trap from EL0 to EL1 then + * that always takes priority over the HSTR_EL2 trap. (If it indicates + * a trap to EL3, then the HSTR_EL2 trap takes priority; if it indicates + * a trap to EL2, then the syndrome is the same either way so we don't + * care whether technically the architecture says that HSTR_EL2 trap or + * the other trap takes priority. So we take the "check HSTR_EL2" path + * for all of those cases.) */ + if (res != CP_ACCESS_OK && ((res & CP_ACCESS_EL_MASK) == 0) && + arm_current_el(env) == 0) { + goto fail; + } + if (!is_a64(env) && arm_current_el(env) < 2 && ri->cp == 15 && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { uint32_t mask = 1 << ri->crn; @@ -661,9 +675,6 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, } } - if (ri->accessfn) { - res = ri->accessfn(env, ri, isread); - } if (likely(res == CP_ACCESS_OK)) { return ri; } From 049edada5e93df096c66a059e1171942238fc472 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:42 +0000 Subject: [PATCH 403/814] target/arm: Make HSTR_EL2 traps take priority over UNDEF-at-EL1 The semantics of HSTR_EL2 require that it traps cpreg accesses to EL2 for: * EL1 accesses * EL0 accesses, if the access is not UNDEFINED when the trap bit is 0 (You can see this in the I_ZFGJP priority ordering, where HSTR_EL2 traps from EL1 to EL2 are priority 12, UNDEFs are priority 13, and HSTR_EL2 traps from EL0 are priority 15.) However, we don't get this right for EL1 accesses which UNDEF because the register doesn't exist at all or because its ri->access bits non-configurably forbid the access. At EL1, check for the HSTR_EL2 trap early, before either of these UNDEF reasons. We have to retain the HSTR_EL2 check in access_check_cp_reg(), because at EL0 any kind of UNDEF-to-EL1 (including "no such register", "bad ri->access" and "ri->accessfn returns 'trap to EL1'") takes precedence over the trap to EL2. But we only need to do that check for EL0 now. Signed-off-by: Peter Maydell Tested-by: Fuad Tabba Reviewed-by: Richard Henderson Message-id: 20230130182459.3309057-7-peter.maydell@linaro.org Message-id: 20230127175507.2895013-7-peter.maydell@linaro.org --- target/arm/op_helper.c | 6 +++++- target/arm/translate.c | 28 +++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 660dae696d..7797a137af 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -658,7 +658,11 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, goto fail; } - if (!is_a64(env) && arm_current_el(env) < 2 && ri->cp == 15 && + /* + * HSTR_EL2 traps from EL1 are checked earlier, in generated code; + * we only need to check here for traps from EL0. + */ + if (!is_a64(env) && arm_current_el(env) == 0 && ri->cp == 15 && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { uint32_t mask = 1 << ri->crn; diff --git a/target/arm/translate.c b/target/arm/translate.c index 9252a464a1..f4bfe55158 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4760,6 +4760,32 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, break; } + if (s->hstr_active && cpnum == 15 && s->current_el == 1) { + /* + * At EL1, check for a HSTR_EL2 trap, which must take precedence + * over the UNDEF for "no such register" or the UNDEF for "access + * permissions forbid this EL1 access". HSTR_EL2 traps from EL0 + * only happen if the cpreg doesn't UNDEF at EL0, so we do those in + * access_check_cp_reg(), after the checks for whether the access + * configurably trapped to EL1. + */ + uint32_t maskbit = is64 ? crm : crn; + + if (maskbit != 4 && maskbit != 14) { + /* T4 and T14 are RES0 so never cause traps */ + TCGv_i32 t; + DisasLabel over = gen_disas_label(s); + + t = load_cpu_offset(offsetoflow32(CPUARMState, cp15.hstr_el2)); + tcg_gen_andi_i32(t, t, 1u << maskbit); + tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, over.label); + tcg_temp_free_i32(t); + + gen_exception_insn(s, 0, EXCP_UDEF, syndrome); + set_disas_label(s, over); + } + } + if (!ri) { /* * Unknown register; this might be a guest error or a QEMU @@ -4788,7 +4814,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, return; } - if (s->hstr_active || ri->accessfn || + if ((s->hstr_active && s->current_el == 0) || ri->accessfn || (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) { /* * Emit code to perform further access permissions checks at From 034bb45ac14602c757c1e9da32196ffa94459c79 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:43 +0000 Subject: [PATCH 404/814] target/arm: Disable HSTR_EL2 traps if EL2 is not enabled The HSTR_EL2 register is not supposed to have an effect unless EL2 is enabled in the current security state. We weren't checking for this, which meant that if the guest set up the HSTR_EL2 register we would incorrectly trap even for accesses from Secure EL0 and EL1. Add the missing checks. (Other places where we look at HSTR_EL2 for the not-in-v8A bits TTEE and TJDBX are already checking that we are in NS EL0 or EL1, so there we alredy know EL2 is enabled.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-8-peter.maydell@linaro.org Message-id: 20230127175507.2895013-8-peter.maydell@linaro.org --- target/arm/helper.c | 2 +- target/arm/op_helper.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6f6772d8e0..6696686921 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11716,7 +11716,7 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_A32(flags, VFPEN, 1); } - if (el < 2 && env->cp15.hstr_el2 && + if (el < 2 && env->cp15.hstr_el2 && arm_is_el2_enabled(env) && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1); } diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 7797a137af..dec03310ad 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -663,6 +663,7 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, * we only need to check here for traps from EL0. */ if (!is_a64(env) && arm_current_el(env) == 0 && ri->cp == 15 && + arm_is_el2_enabled(env) && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { uint32_t mask = 1 << ri->crn; From 15126d9ce2858f472d671960db30aed64fd4f694 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:44 +0000 Subject: [PATCH 405/814] target/arm: Define the FEAT_FGT registers Define the system registers which are provided by the FEAT_FGT fine-grained trap architectural feature: HFGRTR_EL2, HFGWTR_EL2, HDFGRTR_EL2, HDFGWTR_EL2, HFGITR_EL2 All these registers are a set of bit fields, where each bit is set for a trap and clear to not trap on a particular system register access. The R and W register pairs are for system registers, allowing trapping to be done separately for reads and writes; the I register is for system instructions where trapping is on instruction execution. The data storage in the CPU state struct is arranged as a set of arrays rather than separate fields so that when we're looking up the bits for a system register access we can just index into the array rather than having to use a switch to select a named struct member. The later FEAT_FGT2 will add extra elements to these arrays. The field definitions for the new registers are in cpregs.h because in practice the code that needs them is code that also needs the cpregs information; cpu.h is included in a lot more files. We're also going to add some FGT-specific definitions to cpregs.h in the next commit. We do not implement HAFGRTR_EL2, because we don't implement FEAT_AMUv1. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-9-peter.maydell@linaro.org Message-id: 20230127175507.2895013-9-peter.maydell@linaro.org --- target/arm/cpregs.h | 285 ++++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 15 +++ target/arm/helper.c | 40 +++++++ 3 files changed, 340 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 9744179df0..cb3dc56781 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -230,6 +230,291 @@ typedef enum CPAccessResult { CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2), } CPAccessResult; +/* Indexes into fgt_read[] */ +#define FGTREG_HFGRTR 0 +#define FGTREG_HDFGRTR 1 +/* Indexes into fgt_write[] */ +#define FGTREG_HFGWTR 0 +#define FGTREG_HDFGWTR 1 +/* Indexes into fgt_exec[] */ +#define FGTREG_HFGITR 0 + +FIELD(HFGRTR_EL2, AFSR0_EL1, 0, 1) +FIELD(HFGRTR_EL2, AFSR1_EL1, 1, 1) +FIELD(HFGRTR_EL2, AIDR_EL1, 2, 1) +FIELD(HFGRTR_EL2, AMAIR_EL1, 3, 1) +FIELD(HFGRTR_EL2, APDAKEY, 4, 1) +FIELD(HFGRTR_EL2, APDBKEY, 5, 1) +FIELD(HFGRTR_EL2, APGAKEY, 6, 1) +FIELD(HFGRTR_EL2, APIAKEY, 7, 1) +FIELD(HFGRTR_EL2, APIBKEY, 8, 1) +FIELD(HFGRTR_EL2, CCSIDR_EL1, 9, 1) +FIELD(HFGRTR_EL2, CLIDR_EL1, 10, 1) +FIELD(HFGRTR_EL2, CONTEXTIDR_EL1, 11, 1) +FIELD(HFGRTR_EL2, CPACR_EL1, 12, 1) +FIELD(HFGRTR_EL2, CSSELR_EL1, 13, 1) +FIELD(HFGRTR_EL2, CTR_EL0, 14, 1) +FIELD(HFGRTR_EL2, DCZID_EL0, 15, 1) +FIELD(HFGRTR_EL2, ESR_EL1, 16, 1) +FIELD(HFGRTR_EL2, FAR_EL1, 17, 1) +FIELD(HFGRTR_EL2, ISR_EL1, 18, 1) +FIELD(HFGRTR_EL2, LORC_EL1, 19, 1) +FIELD(HFGRTR_EL2, LOREA_EL1, 20, 1) +FIELD(HFGRTR_EL2, LORID_EL1, 21, 1) +FIELD(HFGRTR_EL2, LORN_EL1, 22, 1) +FIELD(HFGRTR_EL2, LORSA_EL1, 23, 1) +FIELD(HFGRTR_EL2, MAIR_EL1, 24, 1) +FIELD(HFGRTR_EL2, MIDR_EL1, 25, 1) +FIELD(HFGRTR_EL2, MPIDR_EL1, 26, 1) +FIELD(HFGRTR_EL2, PAR_EL1, 27, 1) +FIELD(HFGRTR_EL2, REVIDR_EL1, 28, 1) +FIELD(HFGRTR_EL2, SCTLR_EL1, 29, 1) +FIELD(HFGRTR_EL2, SCXTNUM_EL1, 30, 1) +FIELD(HFGRTR_EL2, SCXTNUM_EL0, 31, 1) +FIELD(HFGRTR_EL2, TCR_EL1, 32, 1) +FIELD(HFGRTR_EL2, TPIDR_EL1, 33, 1) +FIELD(HFGRTR_EL2, TPIDRRO_EL0, 34, 1) +FIELD(HFGRTR_EL2, TPIDR_EL0, 35, 1) +FIELD(HFGRTR_EL2, TTBR0_EL1, 36, 1) +FIELD(HFGRTR_EL2, TTBR1_EL1, 37, 1) +FIELD(HFGRTR_EL2, VBAR_EL1, 38, 1) +FIELD(HFGRTR_EL2, ICC_IGRPENN_EL1, 39, 1) +FIELD(HFGRTR_EL2, ERRIDR_EL1, 40, 1) +FIELD(HFGRTR_EL2, ERRSELR_EL1, 41, 1) +FIELD(HFGRTR_EL2, ERXFR_EL1, 42, 1) +FIELD(HFGRTR_EL2, ERXCTLR_EL1, 43, 1) +FIELD(HFGRTR_EL2, ERXSTATUS_EL1, 44, 1) +FIELD(HFGRTR_EL2, ERXMISCN_EL1, 45, 1) +FIELD(HFGRTR_EL2, ERXPFGF_EL1, 46, 1) +FIELD(HFGRTR_EL2, ERXPFGCTL_EL1, 47, 1) +FIELD(HFGRTR_EL2, ERXPFGCDN_EL1, 48, 1) +FIELD(HFGRTR_EL2, ERXADDR_EL1, 49, 1) +FIELD(HFGRTR_EL2, NACCDATA_EL1, 50, 1) +/* 51-53: RES0 */ +FIELD(HFGRTR_EL2, NSMPRI_EL1, 54, 1) +FIELD(HFGRTR_EL2, NTPIDR2_EL0, 55, 1) +/* 56-63: RES0 */ + +/* These match HFGRTR but bits for RO registers are RES0 */ +FIELD(HFGWTR_EL2, AFSR0_EL1, 0, 1) +FIELD(HFGWTR_EL2, AFSR1_EL1, 1, 1) +FIELD(HFGWTR_EL2, AMAIR_EL1, 3, 1) +FIELD(HFGWTR_EL2, APDAKEY, 4, 1) +FIELD(HFGWTR_EL2, APDBKEY, 5, 1) +FIELD(HFGWTR_EL2, APGAKEY, 6, 1) +FIELD(HFGWTR_EL2, APIAKEY, 7, 1) +FIELD(HFGWTR_EL2, APIBKEY, 8, 1) +FIELD(HFGWTR_EL2, CONTEXTIDR_EL1, 11, 1) +FIELD(HFGWTR_EL2, CPACR_EL1, 12, 1) +FIELD(HFGWTR_EL2, CSSELR_EL1, 13, 1) +FIELD(HFGWTR_EL2, ESR_EL1, 16, 1) +FIELD(HFGWTR_EL2, FAR_EL1, 17, 1) +FIELD(HFGWTR_EL2, LORC_EL1, 19, 1) +FIELD(HFGWTR_EL2, LOREA_EL1, 20, 1) +FIELD(HFGWTR_EL2, LORN_EL1, 22, 1) +FIELD(HFGWTR_EL2, LORSA_EL1, 23, 1) +FIELD(HFGWTR_EL2, MAIR_EL1, 24, 1) +FIELD(HFGWTR_EL2, PAR_EL1, 27, 1) +FIELD(HFGWTR_EL2, SCTLR_EL1, 29, 1) +FIELD(HFGWTR_EL2, SCXTNUM_EL1, 30, 1) +FIELD(HFGWTR_EL2, SCXTNUM_EL0, 31, 1) +FIELD(HFGWTR_EL2, TCR_EL1, 32, 1) +FIELD(HFGWTR_EL2, TPIDR_EL1, 33, 1) +FIELD(HFGWTR_EL2, TPIDRRO_EL0, 34, 1) +FIELD(HFGWTR_EL2, TPIDR_EL0, 35, 1) +FIELD(HFGWTR_EL2, TTBR0_EL1, 36, 1) +FIELD(HFGWTR_EL2, TTBR1_EL1, 37, 1) +FIELD(HFGWTR_EL2, VBAR_EL1, 38, 1) +FIELD(HFGWTR_EL2, ICC_IGRPENN_EL1, 39, 1) +FIELD(HFGWTR_EL2, ERRSELR_EL1, 41, 1) +FIELD(HFGWTR_EL2, ERXCTLR_EL1, 43, 1) +FIELD(HFGWTR_EL2, ERXSTATUS_EL1, 44, 1) +FIELD(HFGWTR_EL2, ERXMISCN_EL1, 45, 1) +FIELD(HFGWTR_EL2, ERXPFGCTL_EL1, 47, 1) +FIELD(HFGWTR_EL2, ERXPFGCDN_EL1, 48, 1) +FIELD(HFGWTR_EL2, ERXADDR_EL1, 49, 1) +FIELD(HFGWTR_EL2, NACCDATA_EL1, 50, 1) +FIELD(HFGWTR_EL2, NSMPRI_EL1, 54, 1) +FIELD(HFGWTR_EL2, NTPIDR2_EL0, 55, 1) + +FIELD(HFGITR_EL2, ICIALLUIS, 0, 1) +FIELD(HFGITR_EL2, ICIALLU, 1, 1) +FIELD(HFGITR_EL2, ICIVAU, 2, 1) +FIELD(HFGITR_EL2, DCIVAC, 3, 1) +FIELD(HFGITR_EL2, DCISW, 4, 1) +FIELD(HFGITR_EL2, DCCSW, 5, 1) +FIELD(HFGITR_EL2, DCCISW, 6, 1) +FIELD(HFGITR_EL2, DCCVAU, 7, 1) +FIELD(HFGITR_EL2, DCCVAP, 8, 1) +FIELD(HFGITR_EL2, DCCVADP, 9, 1) +FIELD(HFGITR_EL2, DCCIVAC, 10, 1) +FIELD(HFGITR_EL2, DCZVA, 11, 1) +FIELD(HFGITR_EL2, ATS1E1R, 12, 1) +FIELD(HFGITR_EL2, ATS1E1W, 13, 1) +FIELD(HFGITR_EL2, ATS1E0R, 14, 1) +FIELD(HFGITR_EL2, ATS1E0W, 15, 1) +FIELD(HFGITR_EL2, ATS1E1RP, 16, 1) +FIELD(HFGITR_EL2, ATS1E1WP, 17, 1) +FIELD(HFGITR_EL2, TLBIVMALLE1OS, 18, 1) +FIELD(HFGITR_EL2, TLBIVAE1OS, 19, 1) +FIELD(HFGITR_EL2, TLBIASIDE1OS, 20, 1) +FIELD(HFGITR_EL2, TLBIVAAE1OS, 21, 1) +FIELD(HFGITR_EL2, TLBIVALE1OS, 22, 1) +FIELD(HFGITR_EL2, TLBIVAALE1OS, 23, 1) +FIELD(HFGITR_EL2, TLBIRVAE1OS, 24, 1) +FIELD(HFGITR_EL2, TLBIRVAAE1OS, 25, 1) +FIELD(HFGITR_EL2, TLBIRVALE1OS, 26, 1) +FIELD(HFGITR_EL2, TLBIRVAALE1OS, 27, 1) +FIELD(HFGITR_EL2, TLBIVMALLE1IS, 28, 1) +FIELD(HFGITR_EL2, TLBIVAE1IS, 29, 1) +FIELD(HFGITR_EL2, TLBIASIDE1IS, 30, 1) +FIELD(HFGITR_EL2, TLBIVAAE1IS, 31, 1) +FIELD(HFGITR_EL2, TLBIVALE1IS, 32, 1) +FIELD(HFGITR_EL2, TLBIVAALE1IS, 33, 1) +FIELD(HFGITR_EL2, TLBIRVAE1IS, 34, 1) +FIELD(HFGITR_EL2, TLBIRVAAE1IS, 35, 1) +FIELD(HFGITR_EL2, TLBIRVALE1IS, 36, 1) +FIELD(HFGITR_EL2, TLBIRVAALE1IS, 37, 1) +FIELD(HFGITR_EL2, TLBIRVAE1, 38, 1) +FIELD(HFGITR_EL2, TLBIRVAAE1, 39, 1) +FIELD(HFGITR_EL2, TLBIRVALE1, 40, 1) +FIELD(HFGITR_EL2, TLBIRVAALE1, 41, 1) +FIELD(HFGITR_EL2, TLBIVMALLE1, 42, 1) +FIELD(HFGITR_EL2, TLBIVAE1, 43, 1) +FIELD(HFGITR_EL2, TLBIASIDE1, 44, 1) +FIELD(HFGITR_EL2, TLBIVAAE1, 45, 1) +FIELD(HFGITR_EL2, TLBIVALE1, 46, 1) +FIELD(HFGITR_EL2, TLBIVAALE1, 47, 1) +FIELD(HFGITR_EL2, CFPRCTX, 48, 1) +FIELD(HFGITR_EL2, DVPRCTX, 49, 1) +FIELD(HFGITR_EL2, CPPRCTX, 50, 1) +FIELD(HFGITR_EL2, ERET, 51, 1) +FIELD(HFGITR_EL2, SVC_EL0, 52, 1) +FIELD(HFGITR_EL2, SVC_EL1, 53, 1) +FIELD(HFGITR_EL2, DCCVAC, 54, 1) +FIELD(HFGITR_EL2, NBRBINJ, 55, 1) +FIELD(HFGITR_EL2, NBRBIALL, 56, 1) + +FIELD(HDFGRTR_EL2, DBGBCRN_EL1, 0, 1) +FIELD(HDFGRTR_EL2, DBGBVRN_EL1, 1, 1) +FIELD(HDFGRTR_EL2, DBGWCRN_EL1, 2, 1) +FIELD(HDFGRTR_EL2, DBGWVRN_EL1, 3, 1) +FIELD(HDFGRTR_EL2, MDSCR_EL1, 4, 1) +FIELD(HDFGRTR_EL2, DBGCLAIM, 5, 1) +FIELD(HDFGRTR_EL2, DBGAUTHSTATUS_EL1, 6, 1) +FIELD(HDFGRTR_EL2, DBGPRCR_EL1, 7, 1) +/* 8: RES0: OSLAR_EL1 is WO */ +FIELD(HDFGRTR_EL2, OSLSR_EL1, 9, 1) +FIELD(HDFGRTR_EL2, OSECCR_EL1, 10, 1) +FIELD(HDFGRTR_EL2, OSDLR_EL1, 11, 1) +FIELD(HDFGRTR_EL2, PMEVCNTRN_EL0, 12, 1) +FIELD(HDFGRTR_EL2, PMEVTYPERN_EL0, 13, 1) +FIELD(HDFGRTR_EL2, PMCCFILTR_EL0, 14, 1) +FIELD(HDFGRTR_EL2, PMCCNTR_EL0, 15, 1) +FIELD(HDFGRTR_EL2, PMCNTEN, 16, 1) +FIELD(HDFGRTR_EL2, PMINTEN, 17, 1) +FIELD(HDFGRTR_EL2, PMOVS, 18, 1) +FIELD(HDFGRTR_EL2, PMSELR_EL0, 19, 1) +/* 20: RES0: PMSWINC_EL0 is WO */ +/* 21: RES0: PMCR_EL0 is WO */ +FIELD(HDFGRTR_EL2, PMMIR_EL1, 22, 1) +FIELD(HDFGRTR_EL2, PMBLIMITR_EL1, 23, 1) +FIELD(HDFGRTR_EL2, PMBPTR_EL1, 24, 1) +FIELD(HDFGRTR_EL2, PMBSR_EL1, 25, 1) +FIELD(HDFGRTR_EL2, PMSCR_EL1, 26, 1) +FIELD(HDFGRTR_EL2, PMSEVFR_EL1, 27, 1) +FIELD(HDFGRTR_EL2, PMSFCR_EL1, 28, 1) +FIELD(HDFGRTR_EL2, PMSICR_EL1, 29, 1) +FIELD(HDFGRTR_EL2, PMSIDR_EL1, 30, 1) +FIELD(HDFGRTR_EL2, PMSIRR_EL1, 31, 1) +FIELD(HDFGRTR_EL2, PMSLATFR_EL1, 32, 1) +FIELD(HDFGRTR_EL2, TRC, 33, 1) +FIELD(HDFGRTR_EL2, TRCAUTHSTATUS, 34, 1) +FIELD(HDFGRTR_EL2, TRCAUXCTLR, 35, 1) +FIELD(HDFGRTR_EL2, TRCCLAIM, 36, 1) +FIELD(HDFGRTR_EL2, TRCCNTVRn, 37, 1) +/* 38, 39: RES0 */ +FIELD(HDFGRTR_EL2, TRCID, 40, 1) +FIELD(HDFGRTR_EL2, TRCIMSPECN, 41, 1) +/* 42: RES0: TRCOSLAR is WO */ +FIELD(HDFGRTR_EL2, TRCOSLSR, 43, 1) +FIELD(HDFGRTR_EL2, TRCPRGCTLR, 44, 1) +FIELD(HDFGRTR_EL2, TRCSEQSTR, 45, 1) +FIELD(HDFGRTR_EL2, TRCSSCSRN, 46, 1) +FIELD(HDFGRTR_EL2, TRCSTATR, 47, 1) +FIELD(HDFGRTR_EL2, TRCVICTLR, 48, 1) +/* 49: RES0: TRFCR_EL1 is WO */ +FIELD(HDFGRTR_EL2, TRBBASER_EL1, 50, 1) +FIELD(HDFGRTR_EL2, TRBIDR_EL1, 51, 1) +FIELD(HDFGRTR_EL2, TRBLIMITR_EL1, 52, 1) +FIELD(HDFGRTR_EL2, TRBMAR_EL1, 53, 1) +FIELD(HDFGRTR_EL2, TRBPTR_EL1, 54, 1) +FIELD(HDFGRTR_EL2, TRBSR_EL1, 55, 1) +FIELD(HDFGRTR_EL2, TRBTRG_EL1, 56, 1) +FIELD(HDFGRTR_EL2, PMUSERENR_EL0, 57, 1) +FIELD(HDFGRTR_EL2, PMCEIDN_EL0, 58, 1) +FIELD(HDFGRTR_EL2, NBRBIDR, 59, 1) +FIELD(HDFGRTR_EL2, NBRBCTL, 60, 1) +FIELD(HDFGRTR_EL2, NBRBDATA, 61, 1) +FIELD(HDFGRTR_EL2, NPMSNEVFR_EL1, 62, 1) +FIELD(HDFGRTR_EL2, PMBIDR_EL1, 63, 1) + +/* + * These match HDFGRTR_EL2, but bits for RO registers are RES0. + * A few bits are for WO registers, where the HDFGRTR_EL2 bit is RES0. + */ +FIELD(HDFGWTR_EL2, DBGBCRN_EL1, 0, 1) +FIELD(HDFGWTR_EL2, DBGBVRN_EL1, 1, 1) +FIELD(HDFGWTR_EL2, DBGWCRN_EL1, 2, 1) +FIELD(HDFGWTR_EL2, DBGWVRN_EL1, 3, 1) +FIELD(HDFGWTR_EL2, MDSCR_EL1, 4, 1) +FIELD(HDFGWTR_EL2, DBGCLAIM, 5, 1) +FIELD(HDFGWTR_EL2, DBGPRCR_EL1, 7, 1) +FIELD(HDFGWTR_EL2, OSLAR_EL1, 8, 1) +FIELD(HDFGWTR_EL2, OSLSR_EL1, 9, 1) +FIELD(HDFGWTR_EL2, OSECCR_EL1, 10, 1) +FIELD(HDFGWTR_EL2, OSDLR_EL1, 11, 1) +FIELD(HDFGWTR_EL2, PMEVCNTRN_EL0, 12, 1) +FIELD(HDFGWTR_EL2, PMEVTYPERN_EL0, 13, 1) +FIELD(HDFGWTR_EL2, PMCCFILTR_EL0, 14, 1) +FIELD(HDFGWTR_EL2, PMCCNTR_EL0, 15, 1) +FIELD(HDFGWTR_EL2, PMCNTEN, 16, 1) +FIELD(HDFGWTR_EL2, PMINTEN, 17, 1) +FIELD(HDFGWTR_EL2, PMOVS, 18, 1) +FIELD(HDFGWTR_EL2, PMSELR_EL0, 19, 1) +FIELD(HDFGWTR_EL2, PMSWINC_EL0, 20, 1) +FIELD(HDFGWTR_EL2, PMCR_EL0, 21, 1) +FIELD(HDFGWTR_EL2, PMBLIMITR_EL1, 23, 1) +FIELD(HDFGWTR_EL2, PMBPTR_EL1, 24, 1) +FIELD(HDFGWTR_EL2, PMBSR_EL1, 25, 1) +FIELD(HDFGWTR_EL2, PMSCR_EL1, 26, 1) +FIELD(HDFGWTR_EL2, PMSEVFR_EL1, 27, 1) +FIELD(HDFGWTR_EL2, PMSFCR_EL1, 28, 1) +FIELD(HDFGWTR_EL2, PMSICR_EL1, 29, 1) +FIELD(HDFGWTR_EL2, PMSIRR_EL1, 31, 1) +FIELD(HDFGWTR_EL2, PMSLATFR_EL1, 32, 1) +FIELD(HDFGWTR_EL2, TRC, 33, 1) +FIELD(HDFGWTR_EL2, TRCAUXCTLR, 35, 1) +FIELD(HDFGWTR_EL2, TRCCLAIM, 36, 1) +FIELD(HDFGWTR_EL2, TRCCNTVRn, 37, 1) +FIELD(HDFGWTR_EL2, TRCIMSPECN, 41, 1) +FIELD(HDFGWTR_EL2, TRCOSLAR, 42, 1) +FIELD(HDFGWTR_EL2, TRCPRGCTLR, 44, 1) +FIELD(HDFGWTR_EL2, TRCSEQSTR, 45, 1) +FIELD(HDFGWTR_EL2, TRCSSCSRN, 46, 1) +FIELD(HDFGWTR_EL2, TRCVICTLR, 48, 1) +FIELD(HDFGWTR_EL2, TRFCR_EL1, 49, 1) +FIELD(HDFGWTR_EL2, TRBBASER_EL1, 50, 1) +FIELD(HDFGWTR_EL2, TRBLIMITR_EL1, 52, 1) +FIELD(HDFGWTR_EL2, TRBMAR_EL1, 53, 1) +FIELD(HDFGWTR_EL2, TRBPTR_EL1, 54, 1) +FIELD(HDFGWTR_EL2, TRBSR_EL1, 55, 1) +FIELD(HDFGWTR_EL2, TRBTRG_EL1, 56, 1) +FIELD(HDFGWTR_EL2, PMUSERENR_EL0, 57, 1) +FIELD(HDFGWTR_EL2, NBRBCTL, 60, 1) +FIELD(HDFGWTR_EL2, NBRBDATA, 61, 1) +FIELD(HDFGWTR_EL2, NPMSNEVFR_EL1, 62, 1) + typedef struct ARMCPRegInfo ARMCPRegInfo; /* diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 8cf70693be..063024508a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -529,6 +529,16 @@ typedef struct CPUArchState { uint64_t disr_el1; uint64_t vdisr_el2; uint64_t vsesr_el2; + + /* + * Fine-Grained Trap registers. We store these as arrays so the + * access checking code doesn't have to manually select + * HFGRTR_EL2 vs HFDFGRTR_EL2 etc when looking up the bit to test. + * FEAT_FGT2 will add more elements to these arrays. + */ + uint64_t fgt_read[2]; /* HFGRTR, HDFGRTR */ + uint64_t fgt_write[2]; /* HFGWTR, HDFGWTR */ + uint64_t fgt_exec[1]; /* HFGITR */ } cp15; struct { @@ -4164,6 +4174,11 @@ static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id) return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id)); } +static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0; +} + static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; diff --git a/target/arm/helper.c b/target/arm/helper.c index 6696686921..2052799535 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1869,6 +1869,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_hcx, cpu)) { valid_mask |= SCR_HXEN; } + if (cpu_isar_feature(aa64_fgt, cpu)) { + valid_mask |= SCR_FGTEN; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -7546,6 +7549,39 @@ static const ARMCPRegInfo scxtnum_reginfo[] = { .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, scxtnum_el[3]) }, }; + +static CPAccessResult access_fgt(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 2 && + arm_feature(env, ARM_FEATURE_EL3) && !(env->cp15.scr_el3 & SCR_FGTEN)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo fgt_reginfo[] = { + { .name = "HFGRTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4, + .access = PL2_RW, .accessfn = access_fgt, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HFGRTR]) }, + { .name = "HFGWTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 5, + .access = PL2_RW, .accessfn = access_fgt, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HFGWTR]) }, + { .name = "HDFGRTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 4, + .access = PL2_RW, .accessfn = access_fgt, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HDFGRTR]) }, + { .name = "HDFGWTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 5, + .access = PL2_RW, .accessfn = access_fgt, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HDFGWTR]) }, + { .name = "HFGITR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 6, + .access = PL2_RW, .accessfn = access_fgt, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) }, +}; #endif /* TARGET_AARCH64 */ static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, @@ -8933,6 +8969,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_scxtnum, cpu)) { define_arm_cp_regs(cpu, scxtnum_reginfo); } + + if (cpu_isar_feature(aa64_fgt, cpu)) { + define_arm_cp_regs(cpu, fgt_reginfo); + } #endif if (cpu_isar_feature(any_predinv, cpu)) { From 361c33f6b899a1ddb88a08dc99957419def6086d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:45 +0000 Subject: [PATCH 406/814] target/arm: Implement FGT trapping infrastructure Implement the machinery for fine-grained traps on normal sysregs. Any sysreg with a fine-grained trap will set the new field to indicate which FGT register bit it should trap on. FGT traps only happen when an AArch64 EL2 enables them for an AArch64 EL1. They therefore are only relevant for AArch32 cpregs when the cpreg can be accessed from EL0. The logic in access_check_cp_reg() will check this, so it is safe to add a .fgt marking to an ARM_CP_STATE_BOTH ARMCPRegInfo. The DO_BIT and DO_REV_BIT macros define enum constants FGT_##bitname which can be used to specify the FGT bit, eg .fgt = FGT_AFSR0_EL1 (We assume that there is no bit name duplication across the FGT registers, for brevity's sake.) Subsequent commits will add the .fgt fields to the relevant register definitions and define the FGT_nnn values for them. Note that some of the FGT traps are for instructions that we don't handle via the cpregs mechanisms (mostly these are instruction traps). Those we will have to handle separately. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-10-peter.maydell@linaro.org Message-id: 20230127175507.2895013-10-peter.maydell@linaro.org --- target/arm/cpregs.h | 72 ++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 1 + target/arm/helper.c | 9 +++++ target/arm/internals.h | 20 +++++++++++ target/arm/op_helper.c | 30 ++++++++++++++++ target/arm/translate-a64.c | 3 +- target/arm/translate.c | 2 ++ target/arm/translate.h | 2 ++ 8 files changed, 138 insertions(+), 1 deletion(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index cb3dc56781..8cc12045af 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -515,6 +515,73 @@ FIELD(HDFGWTR_EL2, NBRBCTL, 60, 1) FIELD(HDFGWTR_EL2, NBRBDATA, 61, 1) FIELD(HDFGWTR_EL2, NPMSNEVFR_EL1, 62, 1) +/* Which fine-grained trap bit register to check, if any */ +FIELD(FGT, TYPE, 10, 3) +FIELD(FGT, REV, 9, 1) /* Is bit sense reversed? */ +FIELD(FGT, IDX, 6, 3) /* Index within a uint64_t[] array */ +FIELD(FGT, BITPOS, 0, 6) /* Bit position within the uint64_t */ + +/* + * Macros to define FGT_##bitname enum constants to use in ARMCPRegInfo::fgt + * fields. We assume for brevity's sake that there are no duplicated + * bit names across the various FGT registers. + */ +#define DO_BIT(REG, BITNAME) \ + FGT_##BITNAME = FGT_##REG | R_##REG##_EL2_##BITNAME##_SHIFT + +/* Some bits have reversed sense, so 0 means trap and 1 means not */ +#define DO_REV_BIT(REG, BITNAME) \ + FGT_##BITNAME = FGT_##REG | FGT_REV | R_##REG##_EL2_##BITNAME##_SHIFT + +typedef enum FGTBit { + /* + * These bits tell us which register arrays to use: + * if FGT_R is set then reads are checked against fgt_read[]; + * if FGT_W is set then writes are checked against fgt_write[]; + * if FGT_EXEC is set then all accesses are checked against fgt_exec[]. + * + * For almost all bits in the R/W register pairs, the bit exists in + * both registers for a RW register, in HFGRTR/HDFGRTR for a RO register + * with the corresponding HFGWTR/HDFGTWTR bit being RES0, and vice-versa + * for a WO register. There are unfortunately a couple of exceptions + * (PMCR_EL0, TRFCR_EL1) where the register being trapped is RW but + * the FGT system only allows trapping of writes, not reads. + * + * Note that we arrange these bits so that a 0 FGTBit means "no trap". + */ + FGT_R = 1 << R_FGT_TYPE_SHIFT, + FGT_W = 2 << R_FGT_TYPE_SHIFT, + FGT_EXEC = 4 << R_FGT_TYPE_SHIFT, + FGT_RW = FGT_R | FGT_W, + /* Bit to identify whether trap bit is reversed sense */ + FGT_REV = R_FGT_REV_MASK, + + /* + * If a bit exists in HFGRTR/HDFGRTR then either the register being + * trapped is RO or the bit also exists in HFGWTR/HDFGWTR, so we either + * want to trap for both reads and writes or else it's harmless to mark + * it as trap-on-writes. + * If a bit exists only in HFGWTR/HDFGWTR then either the register being + * trapped is WO, or else it is one of the two oddball special cases + * which are RW but have only a write trap. We mark these as only + * FGT_W so we get the right behaviour for those special cases. + * (If a bit was added in future that provided only a read trap for an + * RW register we'd need to do something special to get the FGT_R bit + * only. But this seems unlikely to happen.) + * + * So for the DO_BIT/DO_REV_BIT macros: use FGT_HFGRTR/FGT_HDFGRTR if + * the bit exists in that register. Otherwise use FGT_HFGWTR/FGT_HDFGWTR. + */ + FGT_HFGRTR = FGT_RW | (FGTREG_HFGRTR << R_FGT_IDX_SHIFT), + FGT_HFGWTR = FGT_W | (FGTREG_HFGWTR << R_FGT_IDX_SHIFT), + FGT_HDFGRTR = FGT_RW | (FGTREG_HDFGRTR << R_FGT_IDX_SHIFT), + FGT_HDFGWTR = FGT_W | (FGTREG_HDFGWTR << R_FGT_IDX_SHIFT), + FGT_HFGITR = FGT_EXEC | (FGTREG_HFGITR << R_FGT_IDX_SHIFT), +} FGTBit; + +#undef DO_BIT +#undef DO_REV_BIT + typedef struct ARMCPRegInfo ARMCPRegInfo; /* @@ -569,6 +636,11 @@ struct ARMCPRegInfo { CPAccessRights access; /* Security state: ARM_CP_SECSTATE_* bits/values */ CPSecureState secure; + /* + * Which fine-grained trap register bit to check, if any. This + * value encodes both the trap register and bit within it. + */ + FGTBit fgt; /* * The opaque pointer passed to define_arm_cp_regs_with_opaque() when * this register was defined: can be used to hand data through to the diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 063024508a..5cc81bec9b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3170,6 +3170,7 @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) /* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */ FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1) FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1) +FIELD(TBFLAG_ANY, FGT_ACTIVE, 12, 1) /* * Bit usage when in AArch32 state, both A- and M-profile. diff --git a/target/arm/helper.c b/target/arm/helper.c index 2052799535..2389e41bd0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11689,6 +11689,7 @@ static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, if (arm_singlestep_active(env)) { DP_TBFLAG_ANY(flags, SS_ACTIVE, 1); } + return flags; } @@ -11761,6 +11762,10 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1); } + if (arm_fgt_active(env, el)) { + DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); + } + if (env->uncached_cpsr & CPSR_IL) { DP_TBFLAG_ANY(flags, PSTATE__IL, 1); } @@ -11895,6 +11900,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, DP_TBFLAG_ANY(flags, PSTATE__IL, 1); } + if (arm_fgt_active(env, el)) { + DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); + } + if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { /* * Set MTE_ACTIVE if any access may be Checked, and leave clear diff --git a/target/arm/internals.h b/target/arm/internals.h index d9555309df..e1e018da46 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1377,4 +1377,24 @@ static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env) ((1 << (1 - 1)) | (1 << (2 - 1)) | \ (1 << (4 - 1)) | (1 << (8 - 1)) | (1 << (16 - 1))) +/* + * Return true if it is possible to take a fine-grained-trap to EL2. + */ +static inline bool arm_fgt_active(CPUARMState *env, int el) +{ + /* + * The Arm ARM only requires the "{E2H,TGE} != {1,1}" test for traps + * that can affect EL0, but it is harmless to do the test also for + * traps on registers that are only accessible at EL1 because if the test + * returns true then we can't be executing at EL1 anyway. + * FGT traps only happen when EL2 is enabled and EL1 is AArch64; + * traps from AArch32 only happen for the EL0 is AArch32 case. + */ + return cpu_isar_feature(aa64_fgt, env_archcpu(env)) && + el < 2 && arm_is_el2_enabled(env) && + arm_el_is_aa64(env, 1) && + (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE) && + (!arm_feature(env, ARM_FEATURE_EL3) || (env->cp15.scr_el3 & SCR_FGTEN)); +} + #endif diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index dec03310ad..3baf8004f6 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -680,6 +680,36 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, } } + /* + * Fine-grained traps also are lower priority than undef-to-EL1, + * higher priority than trap-to-EL3, and we don't care about priority + * order with other EL2 traps because the syndrome value is the same. + */ + if (arm_fgt_active(env, arm_current_el(env))) { + uint64_t trapword = 0; + unsigned int idx = FIELD_EX32(ri->fgt, FGT, IDX); + unsigned int bitpos = FIELD_EX32(ri->fgt, FGT, BITPOS); + bool rev = FIELD_EX32(ri->fgt, FGT, REV); + bool trapbit; + + if (ri->fgt & FGT_EXEC) { + assert(idx < ARRAY_SIZE(env->cp15.fgt_exec)); + trapword = env->cp15.fgt_exec[idx]; + } else if (isread && (ri->fgt & FGT_R)) { + assert(idx < ARRAY_SIZE(env->cp15.fgt_read)); + trapword = env->cp15.fgt_read[idx]; + } else if (!isread && (ri->fgt & FGT_W)) { + assert(idx < ARRAY_SIZE(env->cp15.fgt_write)); + trapword = env->cp15.fgt_write[idx]; + } + + trapbit = extract64(trapword, bitpos, 1); + if (trapbit != rev) { + res = CP_ACCESS_TRAP_EL2; + goto fail; + } + } + if (likely(res == CP_ACCESS_OK)) { return ri; } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 52b1b8a1f0..a47dab4f1d 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1962,7 +1962,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, return; } - if (ri->accessfn) { + if (ri->accessfn || (ri->fgt && s->fgt_active)) { /* Emit code to perform further access permissions checks at * runtime; this may result in an exception. */ @@ -14741,6 +14741,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); + dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; diff --git a/target/arm/translate.c b/target/arm/translate.c index f4bfe55158..3f51dc6a6b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4815,6 +4815,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, } if ((s->hstr_active && s->current_el == 0) || ri->accessfn || + (ri->fgt && s->fgt_active) || (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) { /* * Emit code to perform further access permissions checks at @@ -9415,6 +9416,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); + dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); if (arm_feature(env, ARM_FEATURE_M)) { dc->vfp_enabled = 1; diff --git a/target/arm/translate.h b/target/arm/translate.h index f17f095cbe..599902016d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -130,6 +130,8 @@ typedef struct DisasContext { bool is_nonstreaming; /* True if MVE insns are definitely not predicated by VPR or LTPSIZE */ bool mve_no_pred; + /* True if fine-grained traps are active */ + bool fgt_active; /* * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * < 0, set by the current instruction. From 158c276c7417da68ca46f2df88f1c1f9085eb895 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:46 +0000 Subject: [PATCH 407/814] target/arm: Mark up sysregs for HFGRTR bits 0..11 Mark up the sysreg definitions for the registers trapped by HFGRTR/HFGWTR bits 0..11. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-11-peter.maydell@linaro.org Message-id: 20230127175507.2895013-11-peter.maydell@linaro.org --- target/arm/cpregs.h | 14 ++++++++++++++ target/arm/helper.c | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 8cc12045af..82f2cefff0 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -577,6 +577,20 @@ typedef enum FGTBit { FGT_HDFGRTR = FGT_RW | (FGTREG_HDFGRTR << R_FGT_IDX_SHIFT), FGT_HDFGWTR = FGT_W | (FGTREG_HDFGWTR << R_FGT_IDX_SHIFT), FGT_HFGITR = FGT_EXEC | (FGTREG_HFGITR << R_FGT_IDX_SHIFT), + + /* Trap bits in HFGRTR_EL2 / HFGWTR_EL2, starting from bit 0. */ + DO_BIT(HFGRTR, AFSR0_EL1), + DO_BIT(HFGRTR, AFSR1_EL1), + DO_BIT(HFGRTR, AIDR_EL1), + DO_BIT(HFGRTR, AMAIR_EL1), + DO_BIT(HFGRTR, APDAKEY), + DO_BIT(HFGRTR, APDBKEY), + DO_BIT(HFGRTR, APGAKEY), + DO_BIT(HFGRTR, APIAKEY), + DO_BIT(HFGRTR, APIBKEY), + DO_BIT(HFGRTR, CCSIDR_EL1), + DO_BIT(HFGRTR, CLIDR_EL1), + DO_BIT(HFGRTR, CONTEXTIDR_EL1), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 2389e41bd0..30e54455ac 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -633,6 +633,7 @@ static const ARMCPRegInfo cp_reginfo[] = { { .name = "CONTEXTIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_CONTEXTIDR_EL1, .secure = ARM_CP_SECSTATE_NS, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, @@ -2163,6 +2164,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, .accessfn = access_tid4, + .fgt = FGT_CCSIDR_EL1, .readfn = ccsidr_read, .type = ARM_CP_NO_RAW }, { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, @@ -2179,6 +2181,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid1, + .fgt = FGT_AIDR_EL1, .resetvalue = 0 }, /* * Auxiliary fault status registers: these also are IMPDEF, and we @@ -2187,10 +2190,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "AFSR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_AFSR0_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_AFSR1_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, /* * MAIR can just read-as-written because we don't implement caches @@ -4392,6 +4397,7 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { { .name = "AMAIR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_AMAIR_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, /* AMAIR1 is mapped to AMAIR_EL1[63:32] */ { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1, @@ -7041,42 +7047,52 @@ static const ARMCPRegInfo pauth_reginfo[] = { { .name = "APDAKEYLO_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APDAKEY, .fieldoffset = offsetof(CPUARMState, keys.apda.lo) }, { .name = "APDAKEYHI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 1, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APDAKEY, .fieldoffset = offsetof(CPUARMState, keys.apda.hi) }, { .name = "APDBKEYLO_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 2, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APDBKEY, .fieldoffset = offsetof(CPUARMState, keys.apdb.lo) }, { .name = "APDBKEYHI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 3, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APDBKEY, .fieldoffset = offsetof(CPUARMState, keys.apdb.hi) }, { .name = "APGAKEYLO_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 0, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APGAKEY, .fieldoffset = offsetof(CPUARMState, keys.apga.lo) }, { .name = "APGAKEYHI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 1, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APGAKEY, .fieldoffset = offsetof(CPUARMState, keys.apga.hi) }, { .name = "APIAKEYLO_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 0, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APIAKEY, .fieldoffset = offsetof(CPUARMState, keys.apia.lo) }, { .name = "APIAKEYHI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 1, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APIAKEY, .fieldoffset = offsetof(CPUARMState, keys.apia.hi) }, { .name = "APIBKEYLO_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 2, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APIBKEY, .fieldoffset = offsetof(CPUARMState, keys.apib.lo) }, { .name = "APIBKEYHI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3, .access = PL1_RW, .accessfn = access_pauth, + .fgt = FGT_APIBKEY, .fieldoffset = offsetof(CPUARMState, keys.apib.hi) }, }; @@ -7940,6 +7956,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_tid4, + .fgt = FGT_CLIDR_EL1, .resetvalue = cpu->clidr }; define_one_arm_cp_reg(cpu, &clidr); From b19ed03c4cdf79efbdc5f2241e8cd20e1f11bd3c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:47 +0000 Subject: [PATCH 408/814] target/arm: Mark up sysregs for HFGRTR bits 12..23 Mark up the sysreg definitions for the registers trapped by HFGRTR/HFGWTR bits 12..23. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-12-peter.maydell@linaro.org Message-id: 20230127175507.2895013-12-peter.maydell@linaro.org --- target/arm/cpregs.h | 12 ++++++++++++ target/arm/helper.c | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 82f2cefff0..67d87ae8bf 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -591,6 +591,18 @@ typedef enum FGTBit { DO_BIT(HFGRTR, CCSIDR_EL1), DO_BIT(HFGRTR, CLIDR_EL1), DO_BIT(HFGRTR, CONTEXTIDR_EL1), + DO_BIT(HFGRTR, CPACR_EL1), + DO_BIT(HFGRTR, CSSELR_EL1), + DO_BIT(HFGRTR, CTR_EL0), + DO_BIT(HFGRTR, DCZID_EL0), + DO_BIT(HFGRTR, ESR_EL1), + DO_BIT(HFGRTR, FAR_EL1), + DO_BIT(HFGRTR, ISR_EL1), + DO_BIT(HFGRTR, LORC_EL1), + DO_BIT(HFGRTR, LOREA_EL1), + DO_BIT(HFGRTR, LORID_EL1), + DO_BIT(HFGRTR, LORN_EL1), + DO_BIT(HFGRTR, LORSA_EL1), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 30e54455ac..c059935d0e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -869,6 +869,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, }, { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access, + .fgt = FGT_CPACR_EL1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1), .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read }, }; @@ -2170,6 +2171,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_tid4, + .fgt = FGT_CSSELR_EL1, .writefn = csselr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s), offsetof(CPUARMState, cp15.csselr_ns) } }, @@ -2233,6 +2235,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .resetfn = arm_cp_reset_ignore }, { .name = "ISR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 1, .opc2 = 0, + .fgt = FGT_ISR_EL1, .type = ARM_CP_NO_RAW, .access = PL1_R, .readfn = isr_read }, /* 32 bit ITLB invalidates */ { .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0, @@ -4135,6 +4138,7 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_FAR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, }; @@ -4143,6 +4147,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_ESR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, @@ -5215,6 +5220,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0, .access = PL0_R, .type = ARM_CP_NO_RAW, + .fgt = FGT_DCZID_EL0, .readfn = aa64_dczid_read }, { .name = "DC_ZVA", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 1, @@ -7005,22 +7011,27 @@ static const ARMCPRegInfo lor_reginfo[] = { { .name = "LORSA_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 0, .access = PL1_RW, .accessfn = access_lor_other, + .fgt = FGT_LORSA_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "LOREA_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 1, .access = PL1_RW, .accessfn = access_lor_other, + .fgt = FGT_LOREA_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "LORN_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 2, .access = PL1_RW, .accessfn = access_lor_other, + .fgt = FGT_LORN_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "LORC_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 3, .access = PL1_RW, .accessfn = access_lor_other, + .fgt = FGT_LORC_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "LORID_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7, .access = PL1_R, .accessfn = access_lor_ns, + .fgt = FGT_LORID_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, }; @@ -8619,6 +8630,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0, .access = PL0_R, .accessfn = ctr_el0_access, + .fgt = FGT_CTR_EL0, .type = ARM_CP_CONST, .resetvalue = cpu->ctr }, /* TCMTR and TLBTR exist in v8 but have no 64-bit versions */ { .name = "TCMTR", From 67dd80306cd09ad6daf9570bca94095a743d3467 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:48 +0000 Subject: [PATCH 409/814] target/arm: Mark up sysregs for HFGRTR bits 24..35 Mark up the sysreg definitions for the registers trapped by HFGRTR/HFGWTR bits 24..35. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-13-peter.maydell@linaro.org Message-id: 20230127175507.2895013-13-peter.maydell@linaro.org --- target/arm/cpregs.h | 12 ++++++++++++ target/arm/helper.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 67d87ae8bf..1b219242d5 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -603,6 +603,18 @@ typedef enum FGTBit { DO_BIT(HFGRTR, LORID_EL1), DO_BIT(HFGRTR, LORN_EL1), DO_BIT(HFGRTR, LORSA_EL1), + DO_BIT(HFGRTR, MAIR_EL1), + DO_BIT(HFGRTR, MIDR_EL1), + DO_BIT(HFGRTR, MPIDR_EL1), + DO_BIT(HFGRTR, PAR_EL1), + DO_BIT(HFGRTR, REVIDR_EL1), + DO_BIT(HFGRTR, SCTLR_EL1), + DO_BIT(HFGRTR, SCXTNUM_EL1), + DO_BIT(HFGRTR, SCXTNUM_EL0), + DO_BIT(HFGRTR, TCR_EL1), + DO_BIT(HFGRTR, TPIDR_EL1), + DO_BIT(HFGRTR, TPIDRRO_EL0), + DO_BIT(HFGRTR, TPIDR_EL0), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index c059935d0e..9f6d9e2a3c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2206,6 +2206,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_MAIR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), .resetvalue = 0 }, { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64, @@ -2349,25 +2350,30 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { { .name = "TPIDR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 2, .crn = 13, .crm = 0, .access = PL0_RW, + .fgt = FGT_TPIDR_EL0, .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[0]), .resetvalue = 0 }, { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL0_RW, + .fgt = FGT_TPIDR_EL0, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrurw_s), offsetoflow32(CPUARMState, cp15.tpidrurw_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .opc2 = 3, .crn = 13, .crm = 0, .access = PL0_R | PL1_W, + .fgt = FGT_TPIDRRO_EL0, .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el[0]), .resetvalue = 0}, { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL0_R | PL1_W, + .fgt = FGT_TPIDRRO_EL0, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidruro_s), offsetoflow32(CPUARMState, cp15.tpidruro_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "TPIDR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0, .access = PL1_RW, + .fgt = FGT_TPIDR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[1]), .resetvalue = 0 }, { .name = "TPIDRPRW", .opc1 = 0, .cp = 15, .crn = 13, .crm = 0, .opc2 = 4, .access = PL1_RW, @@ -4164,6 +4170,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_TCR_EL1, .writefn = vmsa_tcr_el12_write, .raw_writefn = raw_write, .resetvalue = 0, @@ -5399,6 +5406,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .type = ARM_CP_ALIAS, .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0, .access = PL1_RW, .resetvalue = 0, + .fgt = FGT_PAR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.par_el[1]), .writefn = par_write }, #endif @@ -7562,10 +7570,12 @@ static const ARMCPRegInfo scxtnum_reginfo[] = { { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7, .access = PL0_RW, .accessfn = access_scxtnum, + .fgt = FGT_SCXTNUM_EL0, .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) }, { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7, .access = PL1_RW, .accessfn = access_scxtnum, + .fgt = FGT_SCXTNUM_EL1, .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, @@ -8604,6 +8614,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr, + .fgt = FGT_MIDR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid), .readfn = midr_read }, /* crn = 0 op1 = 0 crm = 0 op2 = 7 : AArch32 aliases of MIDR */ @@ -8614,6 +8625,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6, .access = PL1_R, .accessfn = access_aa64_tid1, + .fgt = FGT_REVIDR_EL1, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, }; ARMCPRegInfo id_v8_midr_alias_cp_reginfo = { @@ -8785,6 +8797,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo mpidr_cp_reginfo[] = { { .name = "MPIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5, + .fgt = FGT_MPIDR_EL1, .access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW }, }; #ifdef CONFIG_USER_ONLY @@ -8884,6 +8897,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .name = "SCTLR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_SCTLR_EL1, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), offsetof(CPUARMState, cp15.sctlr_ns) }, .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr, From bd8db7d905d19dcd514ace40f41580501c80d51f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:49 +0000 Subject: [PATCH 410/814] target/arm: Mark up sysregs for HFGRTR bits 36..63 Mark up the sysreg definitions for the registers trapped by HFGRTR/HFGWTR bits 36..63. Of these, some correspond to RAS registers which we implement as always-UNDEF: these don't need any extra handling for FGT because the UNDEF-to-EL1 always takes priority over any theoretical FGT-trap-to-EL2. Bit 50 (NACCDATA_EL1) is for the ACCDATA_EL1 register which is part of the FEAT_LS64_ACCDATA feature which we don't yet implement. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-14-peter.maydell@linaro.org Message-id: 20230127175507.2895013-14-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 2 ++ target/arm/cpregs.h | 7 +++++++ target/arm/helper.c | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 9a7fc19099..d07b13eb27 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2378,6 +2378,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, + .fgt = FGT_ICC_IGRPENN_EL1, .readfn = icc_igrpen_read, .writefn = icc_igrpen_write, }, @@ -2386,6 +2387,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_irq_access, + .fgt = FGT_ICC_IGRPENN_EL1, .readfn = icc_igrpen_read, .writefn = icc_igrpen_write, }, diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 1b219242d5..fef8ad08ac 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -615,6 +615,13 @@ typedef enum FGTBit { DO_BIT(HFGRTR, TPIDR_EL1), DO_BIT(HFGRTR, TPIDRRO_EL0), DO_BIT(HFGRTR, TPIDR_EL0), + DO_BIT(HFGRTR, TTBR0_EL1), + DO_BIT(HFGRTR, TTBR1_EL1), + DO_BIT(HFGRTR, VBAR_EL1), + DO_BIT(HFGRTR, ICC_IGRPENN_EL1), + DO_BIT(HFGRTR, ERRIDR_EL1), + DO_REV_BIT(HFGRTR, NSMPRI_EL1), + DO_REV_BIT(HFGRTR, NTPIDR2_EL0), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 9f6d9e2a3c..a48b022def 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4158,12 +4158,14 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_TTBR0_EL1, .writefn = vmsa_ttbr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), offsetof(CPUARMState, cp15.ttbr0_ns) } }, { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1, .access = PL1_RW, .accessfn = access_tvm_trvm, + .fgt = FGT_TTBR1_EL1, .writefn = vmsa_ttbr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) } }, @@ -6488,6 +6490,10 @@ static void disr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) * ERRSELR_EL1 * may generate UNDEFINED, which is the effect we get by not * listing them at all. + * + * These registers have fine-grained trap bits, but UNDEF-to-EL1 + * is higher priority than FGT-to-EL2 so we do not need to list them + * in order to check for an FGT. */ static const ARMCPRegInfo minimal_ras_reginfo[] = { { .name = "DISR_EL1", .state = ARM_CP_STATE_BOTH, @@ -6497,6 +6503,7 @@ static const ARMCPRegInfo minimal_ras_reginfo[] = { { .name = "ERRIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 3, .opc2 = 0, .access = PL1_R, .accessfn = access_terr, + .fgt = FGT_ERRIDR_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1, @@ -6819,6 +6826,7 @@ static const ARMCPRegInfo sme_reginfo[] = { { .name = "TPIDR2_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 5, .access = PL0_RW, .accessfn = access_tpidr2, + .fgt = FGT_NTPIDR2_EL0, .fieldoffset = offsetof(CPUARMState, cp15.tpidr2_el0) }, { .name = "SVCR", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 2, @@ -6856,6 +6864,7 @@ static const ARMCPRegInfo sme_reginfo[] = { { .name = "SMPRI_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 4, .access = PL1_RW, .accessfn = access_esm, + .fgt = FGT_NSMPRI_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5, @@ -8884,6 +8893,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "VBAR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .writefn = vbar_write, + .fgt = FGT_VBAR_EL1, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, From 917b1405c1d87c7710f502661f47508d131ea2ca Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:50 +0000 Subject: [PATCH 411/814] target/arm: Mark up sysregs for HDFGRTR bits 0..11 Mark up the sysreg definitons for the registers trapped by HDFGRTR/HDFGWTR bits 0..11. These cover various debug related registers. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-15-peter.maydell@linaro.org Message-id: 20230127175507.2895013-15-peter.maydell@linaro.org --- target/arm/cpregs.h | 12 ++++++++++++ target/arm/debug_helper.c | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index fef8ad08ac..7c4d07ed9c 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -622,6 +622,18 @@ typedef enum FGTBit { DO_BIT(HFGRTR, ERRIDR_EL1), DO_REV_BIT(HFGRTR, NSMPRI_EL1), DO_REV_BIT(HFGRTR, NTPIDR2_EL0), + + /* Trap bits in HDFGRTR_EL2 / HDFGWTR_EL2, starting from bit 0. */ + DO_BIT(HDFGRTR, DBGBCRN_EL1), + DO_BIT(HDFGRTR, DBGBVRN_EL1), + DO_BIT(HDFGRTR, DBGWCRN_EL1), + DO_BIT(HDFGRTR, DBGWVRN_EL1), + DO_BIT(HDFGRTR, MDSCR_EL1), + DO_BIT(HDFGRTR, DBGCLAIM), + DO_BIT(HDFGWTR, OSLAR_EL1), + DO_BIT(HDFGRTR, OSLSR_EL1), + DO_BIT(HDFGRTR, OSECCR_EL1), + DO_BIT(HDFGRTR, OSDLR_EL1), } FGTBit; #undef DO_BIT diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index cced3f168d..b106746b0e 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -672,6 +672,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_MDSCR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), .resetvalue = 0 }, /* @@ -702,6 +703,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { { .name = "OSECCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_OSECCR_EL1, .type = ARM_CP_CONST, .resetvalue = 0 }, /* * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as @@ -717,16 +719,19 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4, .access = PL1_W, .type = ARM_CP_NO_RAW, .accessfn = access_tdosa, + .fgt = FGT_OSLAR_EL1, .writefn = oslar_write }, { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4, .access = PL1_R, .resetvalue = 10, .accessfn = access_tdosa, + .fgt = FGT_OSLSR_EL1, .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) }, /* Dummy OSDLR_EL1: 32-bit Linux will read this */ { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, .access = PL1_RW, .accessfn = access_tdosa, + .fgt = FGT_OSDLR_EL1, .writefn = osdlr_write, .fieldoffset = offsetof(CPUARMState, cp15.osdlr_el1) }, /* @@ -763,10 +768,12 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6, .type = ARM_CP_ALIAS, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGCLAIM, .writefn = dbgclaimset_write, .readfn = dbgclaimset_read }, { .name = "DBGCLAIMCLR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 6, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGCLAIM, .writefn = dbgclaimclr_write, .raw_writefn = raw_write, .fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) }, }; @@ -1127,12 +1134,14 @@ void define_debug_regs(ARMCPU *cpu) { .name = dbgbvr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGBVRN_EL1, .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), .writefn = dbgbvr_write, .raw_writefn = raw_write }, { .name = dbgbcr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGBCRN_EL1, .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), .writefn = dbgbcr_write, .raw_writefn = raw_write }, @@ -1149,12 +1158,14 @@ void define_debug_regs(ARMCPU *cpu) { .name = dbgwvr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGWVRN_EL1, .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), .writefn = dbgwvr_write, .raw_writefn = raw_write }, { .name = dbgwcr_el1_name, .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, .access = PL1_RW, .accessfn = access_tda, + .fgt = FGT_DBGWCRN_EL1, .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), .writefn = dbgwcr_write, .raw_writefn = raw_write }, From dc780233b60c0e4144e09b01f7060075a3c8ff49 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:51 +0000 Subject: [PATCH 412/814] target/arm: Mark up sysregs for HDFGRTR bits 12..63 Mark up the sysreg definitions for the registers trapped by HDFGRTR/HDFGWTR bits 12..x. Bits 12..22 and bit 58 are for PMU registers. The remaining bits in HDFGRTR/HDFGWTR are for traps on registers that are part of features we don't implement: Bits 23..32 and 63 : FEAT_SPE Bits 33..48 : FEAT_ETE Bits 50..56 : FEAT_TRBE Bits 59..61 : FEAT_BRBE Bit 62 : FEAT_SPEv1p2. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-16-peter.maydell@linaro.org Message-id: 20230127175507.2895013-16-peter.maydell@linaro.org --- target/arm/cpregs.h | 12 ++++++++++++ target/arm/helper.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 7c4d07ed9c..c37e013b8f 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -634,6 +634,18 @@ typedef enum FGTBit { DO_BIT(HDFGRTR, OSLSR_EL1), DO_BIT(HDFGRTR, OSECCR_EL1), DO_BIT(HDFGRTR, OSDLR_EL1), + DO_BIT(HDFGRTR, PMEVCNTRN_EL0), + DO_BIT(HDFGRTR, PMEVTYPERN_EL0), + DO_BIT(HDFGRTR, PMCCFILTR_EL0), + DO_BIT(HDFGRTR, PMCCNTR_EL0), + DO_BIT(HDFGRTR, PMCNTEN), + DO_BIT(HDFGRTR, PMINTEN), + DO_BIT(HDFGRTR, PMOVS), + DO_BIT(HDFGRTR, PMSELR_EL0), + DO_BIT(HDFGWTR, PMSWINC_EL0), + DO_BIT(HDFGWTR, PMCR_EL0), + DO_BIT(HDFGRTR, PMMIR_EL1), + DO_BIT(HDFGRTR, PMCEIDN_EL0), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index a48b022def..2e494b8f92 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2035,21 +2035,25 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcnten), .writefn = pmcntenset_write, .accessfn = pmreg_access, + .fgt = FGT_PMCNTEN, .raw_writefn = raw_write }, { .name = "PMCNTENSET_EL0", .state = ARM_CP_STATE_AA64, .type = ARM_CP_IO, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 1, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMCNTEN, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), .resetvalue = 0, .writefn = pmcntenset_write, .raw_writefn = raw_write }, { .name = "PMCNTENCLR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 2, .access = PL0_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcnten), .accessfn = pmreg_access, + .fgt = FGT_PMCNTEN, .writefn = pmcntenclr_write, .type = ARM_CP_ALIAS | ARM_CP_IO }, { .name = "PMCNTENCLR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 2, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMCNTEN, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcnten), .writefn = pmcntenclr_write }, @@ -2057,41 +2061,49 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL0_RW, .type = ARM_CP_IO, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmovsr), .accessfn = pmreg_access, + .fgt = FGT_PMOVS, .writefn = pmovsr_write, .raw_writefn = raw_write }, { .name = "PMOVSCLR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 3, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMOVS, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), .writefn = pmovsr_write, .raw_writefn = raw_write }, { .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4, .access = PL0_W, .accessfn = pmreg_access_swinc, + .fgt = FGT_PMSWINC_EL0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .writefn = pmswinc_write }, { .name = "PMSWINC_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 4, .access = PL0_W, .accessfn = pmreg_access_swinc, + .fgt = FGT_PMSWINC_EL0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .writefn = pmswinc_write }, { .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5, .access = PL0_RW, .type = ARM_CP_ALIAS, + .fgt = FGT_PMSELR_EL0, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmselr), .accessfn = pmreg_access_selr, .writefn = pmselr_write, .raw_writefn = raw_write}, { .name = "PMSELR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 5, .access = PL0_RW, .accessfn = pmreg_access_selr, + .fgt = FGT_PMSELR_EL0, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmselr), .writefn = pmselr_write, .raw_writefn = raw_write, }, { .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0, .access = PL0_RW, .resetvalue = 0, .type = ARM_CP_ALIAS | ARM_CP_IO, + .fgt = FGT_PMCCNTR_EL0, .readfn = pmccntr_read, .writefn = pmccntr_write32, .accessfn = pmreg_access_ccntr }, { .name = "PMCCNTR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 0, .access = PL0_RW, .accessfn = pmreg_access_ccntr, + .fgt = FGT_PMCCNTR_EL0, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c15_ccnt), .readfn = pmccntr_read, .writefn = pmccntr_write, @@ -2099,32 +2111,38 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "PMCCFILTR", .cp = 15, .opc1 = 0, .crn = 14, .crm = 15, .opc2 = 7, .writefn = pmccfiltr_write_a32, .readfn = pmccfiltr_read_a32, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMCCFILTR_EL0, .type = ARM_CP_ALIAS | ARM_CP_IO, .resetvalue = 0, }, { .name = "PMCCFILTR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 15, .opc2 = 7, .writefn = pmccfiltr_write, .raw_writefn = raw_write, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMCCFILTR_EL0, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.pmccfiltr_el0), .resetvalue = 0, }, { .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1, .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO, .accessfn = pmreg_access, + .fgt = FGT_PMEVTYPERN_EL0, .writefn = pmxevtyper_write, .readfn = pmxevtyper_read }, { .name = "PMXEVTYPER_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 1, .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO, .accessfn = pmreg_access, + .fgt = FGT_PMEVTYPERN_EL0, .writefn = pmxevtyper_write, .readfn = pmxevtyper_read }, { .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2, .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO, .accessfn = pmreg_access_xevcntr, + .fgt = FGT_PMEVCNTRN_EL0, .writefn = pmxevcntr_write, .readfn = pmxevcntr_read }, { .name = "PMXEVCNTR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 2, .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO, .accessfn = pmreg_access_xevcntr, + .fgt = FGT_PMEVCNTRN_EL0, .writefn = pmxevcntr_write, .readfn = pmxevcntr_read }, { .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0, .access = PL0_R | PL1_RW, .accessfn = access_tpm, @@ -2139,6 +2157,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .writefn = pmuserenr_write, .raw_writefn = raw_write }, { .name = "PMINTENSET", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .accessfn = access_tpm, + .fgt = FGT_PMINTEN, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pminten), .resetvalue = 0, @@ -2146,18 +2165,21 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "PMINTENSET_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 1, .access = PL1_RW, .accessfn = access_tpm, + .fgt = FGT_PMINTEN, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenset_write, .raw_writefn = raw_write, .resetvalue = 0x0 }, { .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2, .access = PL1_RW, .accessfn = access_tpm, + .fgt = FGT_PMINTEN, .type = ARM_CP_ALIAS | ARM_CP_IO | ARM_CP_NO_RAW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write, }, { .name = "PMINTENCLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 2, .access = PL1_RW, .accessfn = access_tpm, + .fgt = FGT_PMINTEN, .type = ARM_CP_ALIAS | ARM_CP_IO | ARM_CP_NO_RAW, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write }, @@ -2293,6 +2315,7 @@ static const ARMCPRegInfo pmovsset_cp_reginfo[] = { /* PMOVSSET is not implemented in v7 before v7ve */ { .name = "PMOVSSET", .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 3, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMOVS, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmovsr), .writefn = pmovsset_write, @@ -2300,6 +2323,7 @@ static const ARMCPRegInfo pmovsset_cp_reginfo[] = { { .name = "PMOVSSET_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 14, .opc2 = 3, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMOVS, .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr), .writefn = pmovsset_write, @@ -6884,6 +6908,7 @@ static void define_pmu_regs(ARMCPU *cpu) ARMCPRegInfo pmcr = { .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0, .access = PL0_RW, + .fgt = FGT_PMCR_EL0, .type = ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmcr), .accessfn = pmreg_access, .writefn = pmcr_write, @@ -6893,6 +6918,7 @@ static void define_pmu_regs(ARMCPU *cpu) .name = "PMCR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 0, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMCR_EL0, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr), .resetvalue = cpu->isar.reset_pmcr_el0, @@ -6910,23 +6936,27 @@ static void define_pmu_regs(ARMCPU *cpu) { .name = pmevcntr_name, .cp = 15, .crn = 14, .crm = 8 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7, .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS, + .fgt = FGT_PMEVCNTRN_EL0, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, .accessfn = pmreg_access_xevcntr }, { .name = pmevcntr_el0_name, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 8 | (3 & (i >> 3)), .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access_xevcntr, .type = ARM_CP_IO, + .fgt = FGT_PMEVCNTRN_EL0, .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn, .raw_readfn = pmevcntr_rawread, .raw_writefn = pmevcntr_rawwrite }, { .name = pmevtyper_name, .cp = 15, .crn = 14, .crm = 12 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7, .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS, + .fgt = FGT_PMEVTYPERN_EL0, .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn, .accessfn = pmreg_access }, { .name = pmevtyper_el0_name, .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 12 | (3 & (i >> 3)), .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access, + .fgt = FGT_PMEVTYPERN_EL0, .type = ARM_CP_IO, .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn, .raw_writefn = pmevtyper_rawwrite }, @@ -6942,10 +6972,12 @@ static void define_pmu_regs(ARMCPU *cpu) { .name = "PMCEID2", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = extract64(cpu->pmceid0, 32, 32) }, { .name = "PMCEID3", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 5, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = extract64(cpu->pmceid1, 32, 32) }, }; define_arm_cp_regs(cpu, v81_pmu_regs); @@ -6955,6 +6987,7 @@ static void define_pmu_regs(ARMCPU *cpu) .name = "PMMIR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 6, .access = PL1_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMMIR_EL1, .resetvalue = 0 }; define_one_arm_cp_reg(cpu, &v84_pmmir); @@ -8251,18 +8284,22 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "PMCEID0", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 6, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = extract64(cpu->pmceid0, 0, 32) }, { .name = "PMCEID0_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 6, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = cpu->pmceid0 }, { .name = "PMCEID1", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 7, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = extract64(cpu->pmceid1, 0, 32) }, { .name = "PMCEID1_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7, .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST, + .fgt = FGT_PMCEIDN_EL0, .resetvalue = cpu->pmceid1 }, }; #ifdef CONFIG_USER_ONLY From dd3456531924cfa892e44868b3de3b72459f78d9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:52 +0000 Subject: [PATCH 413/814] target/arm: Mark up sysregs for HFGITR bits 0..11 Mark up the sysreg definitions for the system instructions trapped by HFGITR bits 0..11. These bits cover various cache maintenance operations. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-17-peter.maydell@linaro.org Message-id: 20230127175507.2895013-17-peter.maydell@linaro.org --- target/arm/cpregs.h | 14 ++++++++++++++ target/arm/helper.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index c37e013b8f..6596c2a123 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -646,6 +646,20 @@ typedef enum FGTBit { DO_BIT(HDFGWTR, PMCR_EL0), DO_BIT(HDFGRTR, PMMIR_EL1), DO_BIT(HDFGRTR, PMCEIDN_EL0), + + /* Trap bits in HFGITR_EL2, starting from bit 0 */ + DO_BIT(HFGITR, ICIALLUIS), + DO_BIT(HFGITR, ICIALLU), + DO_BIT(HFGITR, ICIVAU), + DO_BIT(HFGITR, DCIVAC), + DO_BIT(HFGITR, DCISW), + DO_BIT(HFGITR, DCCSW), + DO_BIT(HFGITR, DCCISW), + DO_BIT(HFGITR, DCCVAU), + DO_BIT(HFGITR, DCCVAP), + DO_BIT(HFGITR, DCCVADP), + DO_BIT(HFGITR, DCCIVAC), + DO_BIT(HFGITR, DCZVA), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 2e494b8f92..51866ba70e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5261,6 +5261,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY /* Avoid overhead of an access check that always passes in user-mode */ .accessfn = aa64_zva_access, + .fgt = FGT_DCZVA, #endif }, { .name = "CURRENTEL", .state = ARM_CP_STATE_AA64, @@ -5270,21 +5271,26 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "IC_IALLUIS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, + .fgt = FGT_ICIALLUIS, .accessfn = access_ticab }, { .name = "IC_IALLU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, + .fgt = FGT_ICIALLU, .accessfn = access_tocu }, { .name = "IC_IVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 5, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, + .fgt = FGT_ICIVAU, .accessfn = access_tocu }, { .name = "DC_IVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, .access = PL1_W, .accessfn = aa64_cacheop_poc_access, + .fgt = FGT_DCIVAC, .type = ARM_CP_NOP }, { .name = "DC_ISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2, + .fgt = FGT_DCISW, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, { .name = "DC_CVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 1, @@ -5292,17 +5298,21 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, + .fgt = FGT_DCCSW, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, { .name = "DC_CVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, + .fgt = FGT_DCCVAU, .accessfn = access_tocu }, { .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, + .fgt = FGT_DCCIVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, + .fgt = FGT_DCCISW, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, /* TLBI operations */ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, @@ -7413,6 +7423,7 @@ static const ARMCPRegInfo dcpop_reg[] = { { .name = "DC_CVAP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, + .fgt = FGT_DCCVAP, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, }; @@ -7420,6 +7431,7 @@ static const ARMCPRegInfo dcpodp_reg[] = { { .name = "DC_CVADP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, + .fgt = FGT_DCCVADP, .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, }; #endif /*CONFIG_USER_ONLY*/ @@ -7499,28 +7511,36 @@ static const ARMCPRegInfo mte_reginfo[] = { { .name = "DC_IGVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 3, .type = ARM_CP_NOP, .access = PL1_W, + .fgt = FGT_DCIVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_IGSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 4, + .fgt = FGT_DCISW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DC_IGDVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 5, .type = ARM_CP_NOP, .access = PL1_W, + .fgt = FGT_DCIVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_IGDSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 6, + .fgt = FGT_DCISW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DC_CGSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 4, + .fgt = FGT_DCCSW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DC_CGDSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 6, + .fgt = FGT_DCCSW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DC_CIGSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 4, + .fgt = FGT_DCCISW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DC_CIGDSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6, + .fgt = FGT_DCCISW, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, }; @@ -7542,26 +7562,32 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { { .name = "DC_CGVAP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 3, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVAP, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CGDVAP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 5, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVAP, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CGVADP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 3, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVADP, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CGDVADP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 5, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVADP, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CIGVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 3, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCIVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CIGDVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 5, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCIVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_GVA", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 3, @@ -7569,6 +7595,7 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { #ifndef CONFIG_USER_ONLY /* Avoid overhead of an access check that always passes in user-mode */ .accessfn = aa64_zva_access, + .fgt = FGT_DCZVA, #endif }, { .name = "DC_GZVA", .state = ARM_CP_STATE_AA64, @@ -7577,6 +7604,7 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { #ifndef CONFIG_USER_ONLY /* Avoid overhead of an access check that always passes in user-mode */ .accessfn = aa64_zva_access, + .fgt = FGT_DCZVA, #endif }, }; From 132c98cd93fba32e8535efae3a4675579b217ea1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:53 +0000 Subject: [PATCH 414/814] target/arm: Mark up sysregs for HFGITR bits 12..17 Mark up the sysreg definitions for the system instructions trapped by HFGITR bits 12..17. These bits cover AT address translation instructions. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-18-peter.maydell@linaro.org Message-id: 20230127175507.2895013-18-peter.maydell@linaro.org --- target/arm/cpregs.h | 6 ++++++ target/arm/helper.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 6596c2a123..1f74308ef5 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -660,6 +660,12 @@ typedef enum FGTBit { DO_BIT(HFGITR, DCCVADP), DO_BIT(HFGITR, DCCIVAC), DO_BIT(HFGITR, DCZVA), + DO_BIT(HFGITR, ATS1E1R), + DO_BIT(HFGITR, ATS1E1W), + DO_BIT(HFGITR, ATS1E0R), + DO_BIT(HFGITR, ATS1E0W), + DO_BIT(HFGITR, ATS1E1RP), + DO_BIT(HFGITR, ATS1E1WP), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 51866ba70e..8b9c7fcc3a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5400,18 +5400,22 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E1R, .writefn = ats_write64 }, { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E1W, .writefn = ats_write64 }, { .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E0R, .writefn = ats_write64 }, { .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E0W, .writefn = ats_write64 }, { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4, @@ -7880,10 +7884,12 @@ static const ARMCPRegInfo ats1e1_reginfo[] = { { .name = "AT_S1E1RP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E1RP, .writefn = ats_write64 }, { .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1, .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt = FGT_ATS1E1WP, .writefn = ats_write64 }, }; From bf2f0625f822f147f6a50204983c9945d416b338 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:54 +0000 Subject: [PATCH 415/814] target/arm: Mark up sysregs for HFGITR bits 18..47 Mark up the sysreg definitions for the system instructions trapped by HFGITR bits 18..47. These bits cover TLBI TLB maintenance instructions. (If we implemented FEAT_XS we would need to trap some of the instructions added by that feature using these bits; but we don't yet, so will need to add the .fgt markup when we do.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-19-peter.maydell@linaro.org Message-id: 20230127175507.2895013-19-peter.maydell@linaro.org --- target/arm/cpregs.h | 30 ++++++++++++++++++++++++++++++ target/arm/helper.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 1f74308ef5..2e5ac6b4f9 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -666,6 +666,36 @@ typedef enum FGTBit { DO_BIT(HFGITR, ATS1E0W), DO_BIT(HFGITR, ATS1E1RP), DO_BIT(HFGITR, ATS1E1WP), + DO_BIT(HFGITR, TLBIVMALLE1OS), + DO_BIT(HFGITR, TLBIVAE1OS), + DO_BIT(HFGITR, TLBIASIDE1OS), + DO_BIT(HFGITR, TLBIVAAE1OS), + DO_BIT(HFGITR, TLBIVALE1OS), + DO_BIT(HFGITR, TLBIVAALE1OS), + DO_BIT(HFGITR, TLBIRVAE1OS), + DO_BIT(HFGITR, TLBIRVAAE1OS), + DO_BIT(HFGITR, TLBIRVALE1OS), + DO_BIT(HFGITR, TLBIRVAALE1OS), + DO_BIT(HFGITR, TLBIVMALLE1IS), + DO_BIT(HFGITR, TLBIVAE1IS), + DO_BIT(HFGITR, TLBIASIDE1IS), + DO_BIT(HFGITR, TLBIVAAE1IS), + DO_BIT(HFGITR, TLBIVALE1IS), + DO_BIT(HFGITR, TLBIVAALE1IS), + DO_BIT(HFGITR, TLBIRVAE1IS), + DO_BIT(HFGITR, TLBIRVAAE1IS), + DO_BIT(HFGITR, TLBIRVALE1IS), + DO_BIT(HFGITR, TLBIRVAALE1IS), + DO_BIT(HFGITR, TLBIRVAE1), + DO_BIT(HFGITR, TLBIRVAAE1), + DO_BIT(HFGITR, TLBIRVALE1), + DO_BIT(HFGITR, TLBIRVAALE1), + DO_BIT(HFGITR, TLBIVMALLE1), + DO_BIT(HFGITR, TLBIVAE1), + DO_BIT(HFGITR, TLBIASIDE1), + DO_BIT(HFGITR, TLBIVAAE1), + DO_BIT(HFGITR, TLBIVALE1), + DO_BIT(HFGITR, TLBIVAALE1), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 8b9c7fcc3a..5b9cc087e2 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5318,50 +5318,62 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVMALLE1IS, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAE1IS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIASIDE1IS, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAAE1IS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVALE1IS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAALE1IS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVMALLE1, .writefn = tlbi_aa64_vmalle1_write }, { .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAE1, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIASIDE1, .writefn = tlbi_aa64_vmalle1_write }, { .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAAE1, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVALE1, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAALE1, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, @@ -7175,50 +7187,62 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { { .name = "TLBI_RVAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 1, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAE1IS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAAE1IS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVALE1IS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAALE1IS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAE1OS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAAE1OS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVALE1OS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAALE1OS, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAE1, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVAAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAAE1, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVALE1, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RVAALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIRVAALE1, .writefn = tlbi_aa64_rvae1_write }, { .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2, @@ -7290,26 +7314,32 @@ static const ARMCPRegInfo tlbios_reginfo[] = { { .name = "TLBI_VMALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVMALLE1OS, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1, + .fgt = FGT_TLBIVAE1OS, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIASIDE1OS, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAAE1OS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVALE1OS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7, .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, + .fgt = FGT_TLBIVAALE1OS, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, From 950037e280e80d9204a4bced5b6f4575b9c0d94b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:55 +0000 Subject: [PATCH 416/814] target/arm: Mark up sysregs for HFGITR bits 48..63 Mark up the sysreg definitions for the system instructions trapped by HFGITR bits 48..63. Some of these bits are for trapping instructions which are not in the system instruction encoding (i.e. which are not handled by the ARMCPRegInfo mechanism): * ERET, ERETAA, ERETAB * SVC We will have to handle those separately and manually. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-20-peter.maydell@linaro.org Message-id: 20230127175507.2895013-20-peter.maydell@linaro.org --- target/arm/cpregs.h | 4 ++++ target/arm/helper.c | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 2e5ac6b4f9..efcf9181b9 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -696,6 +696,10 @@ typedef enum FGTBit { DO_BIT(HFGITR, TLBIVAAE1), DO_BIT(HFGITR, TLBIVALE1), DO_BIT(HFGITR, TLBIVAALE1), + DO_BIT(HFGITR, CFPRCTX), + DO_BIT(HFGITR, DVPRCTX), + DO_BIT(HFGITR, CPPRCTX), + DO_BIT(HFGITR, DCCVAC), } FGTBit; #undef DO_BIT diff --git a/target/arm/helper.c b/target/arm/helper.c index 5b9cc087e2..c0403aadae 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5295,6 +5295,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DC_CVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, + .fgt = FGT_DCCVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, @@ -7588,10 +7589,12 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = { { .name = "DC_CGVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 3, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CGDVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 5, .type = ARM_CP_NOP, .access = PL0_W, + .fgt = FGT_DCCVAC, .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CGVAP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 3, @@ -7747,24 +7750,30 @@ static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, static const ARMCPRegInfo predinv_reginfo[] = { { .name = "CFP_RCTX", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 4, + .fgt = FGT_CFPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, { .name = "DVP_RCTX", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 5, + .fgt = FGT_DVPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, { .name = "CPP_RCTX", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 7, + .fgt = FGT_CPPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, /* * Note the AArch32 opcodes have a different OPC1. */ { .name = "CFPRCTX", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 4, + .fgt = FGT_CFPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, { .name = "DVPRCTX", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 5, + .fgt = FGT_DVPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, { .name = "CPPRCTX", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 7, + .fgt = FGT_CPPRCTX, .type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv }, }; From 5572f7557fdd1b5c36aee899b7e86fda66c2babf Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:56 +0000 Subject: [PATCH 417/814] target/arm: Implement the HFGITR_EL2.ERET trap Implement the HFGITR_EL2.ERET fine-grained trap. This traps execution from AArch64 EL1 of ERET, ERETAA and ERETAB. The trap is reported with a syndrome value of 0x1a. The trap must take precedence over a possible pointer-authentication trap for ERETAA and ERETAB. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-21-peter.maydell@linaro.org Message-id: 20230127175507.2895013-21-peter.maydell@linaro.org --- target/arm/cpu.h | 1 + target/arm/helper.c | 3 +++ target/arm/syndrome.h | 10 ++++++++++ target/arm/translate-a64.c | 10 ++++++++++ target/arm/translate.h | 2 ++ 5 files changed, 26 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5cc81bec9b..ec2a7716ce 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3245,6 +3245,7 @@ FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1) FIELD(TBFLAG_A64, SVL, 24, 4) /* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */ FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1) +FIELD(TBFLAG_A64, FGT_ERET, 29, 1) /* * Helpers for using the above. diff --git a/target/arm/helper.c b/target/arm/helper.c index c0403aadae..6151c77505 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12065,6 +12065,9 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, if (arm_fgt_active(env, el)) { DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); + if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) { + DP_TBFLAG_A64(flags, FGT_ERET, 1); + } } if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index 73df5e3793..d27d1bc31f 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -48,6 +48,7 @@ enum arm_exception_class { EC_AA64_SMC = 0x17, EC_SYSTEMREGISTERTRAP = 0x18, EC_SVEACCESSTRAP = 0x19, + EC_ERETTRAP = 0x1a, EC_SMETRAP = 0x1d, EC_INSNABORT = 0x20, EC_INSNABORT_SAME_EL = 0x21, @@ -215,6 +216,15 @@ static inline uint32_t syn_sve_access_trap(void) return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT; } +/* + * eret_op is bits [1:0] of the ERET instruction, so: + * 0 for ERET, 2 for ERETAA, 3 for ERETAB. + */ +static inline uint32_t syn_erettrap(int eret_op) +{ + return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op; +} + static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) { return (EC_SMETRAP << ARM_EL_EC_SHIFT) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a47dab4f1d..11bfa3f717 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2385,6 +2385,10 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) if (op4 != 0) { goto do_unallocated; } + if (s->fgt_eret) { + gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(op3), 2); + return; + } dst = tcg_temp_new_i64(); tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUARMState, elr_el[s->current_el])); @@ -2398,6 +2402,11 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn) if (rn != 0x1f || op4 != 0x1f) { goto do_unallocated; } + /* The FGT trap takes precedence over an auth trap. */ + if (s->fgt_eret) { + gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(op3), 2); + return; + } dst = tcg_temp_new_i64(); tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUARMState, elr_el[s->current_el])); @@ -14742,6 +14751,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); + dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; diff --git a/target/arm/translate.h b/target/arm/translate.h index 599902016d..62a7706eab 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -132,6 +132,8 @@ typedef struct DisasContext { bool mve_no_pred; /* True if fine-grained traps are active */ bool fgt_active; + /* True if fine-grained trap on ERET is enabled */ + bool fgt_eret; /* * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * < 0, set by the current instruction. From 34a8a07e57bba6df2c1c67cc9bd3e80706ce4a54 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:57 +0000 Subject: [PATCH 418/814] target/arm: Implement the HFGITR_EL2.SVC_EL0 and SVC_EL1 traps Implement the HFGITR_EL2.SVC_EL0 and SVC_EL1 fine-grained traps. These trap execution of the SVC instruction from AArch32 and AArch64. (As usual, AArch32 can only trap from EL0, as fine grained traps are disabled with an AArch32 EL1.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-22-peter.maydell@linaro.org Message-id: 20230127175507.2895013-22-peter.maydell@linaro.org --- target/arm/cpu.h | 1 + target/arm/helper.c | 20 ++++++++++++++++++++ target/arm/translate-a64.c | 9 ++++++++- target/arm/translate.c | 12 +++++++++--- target/arm/translate.h | 2 ++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ec2a7716ce..7bc97fece9 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3171,6 +3171,7 @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1) FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1) FIELD(TBFLAG_ANY, FGT_ACTIVE, 12, 1) +FIELD(TBFLAG_ANY, FGT_SVC, 13, 1) /* * Bit usage when in AArch32 state, both A- and M-profile. diff --git a/target/arm/helper.c b/target/arm/helper.c index 6151c77505..c62ed05c12 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11842,6 +11842,20 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } +static inline bool fgt_svc(CPUARMState *env, int el) +{ + /* + * Assuming fine-grained-traps are active, return true if we + * should be trapping on SVC instructions. Only AArch64 can + * trap on an SVC at EL1, but we don't need to special-case this + * because if this is AArch32 EL1 then arm_fgt_active() is false. + * We also know el is 0 or 1. + */ + return el == 0 ? + FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, SVC_EL0) : + FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, SVC_EL1); +} + static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx, CPUARMTBFlags flags) @@ -11927,6 +11941,9 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, if (arm_fgt_active(env, el)) { DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); + if (fgt_svc(env, el)) { + DP_TBFLAG_ANY(flags, FGT_SVC, 1); + } } if (env->uncached_cpsr & CPSR_IL) { @@ -12068,6 +12085,9 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) { DP_TBFLAG_A64(flags, FGT_ERET, 1); } + if (fgt_svc(env, el)) { + DP_TBFLAG_ANY(flags, FGT_SVC, 1); + } } if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 11bfa3f717..bbfadb7c2e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2179,6 +2179,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) int opc = extract32(insn, 21, 3); int op2_ll = extract32(insn, 0, 5); int imm16 = extract32(insn, 5, 16); + uint32_t syndrome; switch (opc) { case 0: @@ -2189,8 +2190,13 @@ static void disas_exc(DisasContext *s, uint32_t insn) */ switch (op2_ll) { case 1: /* SVC */ + syndrome = syn_aa64_svc(imm16); + if (s->fgt_svc) { + gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2); + break; + } gen_ss_advance(s); - gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16)); + gen_exception_insn(s, 4, EXCP_SWI, syndrome); break; case 2: /* HVC */ if (s->current_el == 0) { @@ -14751,6 +14757,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); + dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC); dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); diff --git a/target/arm/translate.c b/target/arm/translate.c index 3f51dc6a6b..c23a3462bf 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8834,9 +8834,14 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a) (a->imm == semihost_imm)) { gen_exception_internal_insn(s, EXCP_SEMIHOST); } else { - gen_update_pc(s, curr_insn_len(s)); - s->svc_imm = a->imm; - s->base.is_jmp = DISAS_SWI; + if (s->fgt_svc) { + uint32_t syndrome = syn_aa32_svc(a->imm, s->thumb); + gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2); + } else { + gen_update_pc(s, curr_insn_len(s)); + s->svc_imm = a->imm; + s->base.is_jmp = DISAS_SWI; + } } return true; } @@ -9417,6 +9422,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); + dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC); if (arm_feature(env, ARM_FEATURE_M)) { dc->vfp_enabled = 1; diff --git a/target/arm/translate.h b/target/arm/translate.h index 62a7706eab..3717824b75 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -134,6 +134,8 @@ typedef struct DisasContext { bool fgt_active; /* True if fine-grained trap on ERET is enabled */ bool fgt_eret; + /* True if fine-grained trap on SVC is enabled */ + bool fgt_svc; /* * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * < 0, set by the current instruction. From 1748ef03c562dd4e5222e6d665142b25c0cfb1d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:58 +0000 Subject: [PATCH 419/814] target/arm: Implement MDCR_EL2.TDCC and MDCR_EL3.TDCC traps FEAT_FGT also implements an extra trap bit in the MDCR_EL2 and MDCR_EL3 registers: bit TDCC enables trapping of use of the Debug Comms Channel registers OSDTRRX_EL1, OSDTRTX_EL1, MDCCSR_EL0, MDCCINT_EL0, DBGDTR_EL0, DBGDTRRX_EL0 and DBGDTRTX_EL0 (and their AArch32 equivalents). This trapping is independent of whether fine-grained traps are enabled or not. Implement these extra traps. (We don't implement DBGDTR_EL0, DBGDTRRX_EL0 and DBGDTRTX_EL0.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-23-peter.maydell@linaro.org Message-id: 20230127175507.2895013-23-peter.maydell@linaro.org --- target/arm/debug_helper.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index b106746b0e..3c671c88c1 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -599,6 +599,33 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* + * Check for traps to Debug Comms Channel registers. If FEAT_FGT + * is implemented then these are controlled by MDCR_EL2.TDCC for + * EL2 and MDCR_EL3.TDCC for EL3. They are also controlled by + * the general debug access trap bits MDCR_EL2.TDA and MDCR_EL3.TDA. + */ +static CPAccessResult access_tdcc(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el = arm_current_el(env); + uint64_t mdcr_el2 = arm_mdcr_el2_eff(env); + bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) || + (arm_hcr_el2_eff(env) & HCR_TGE); + bool mdcr_el2_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) && + (mdcr_el2 & MDCR_TDCC); + bool mdcr_el3_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) && + (env->cp15.mdcr_el3 & MDCR_TDCC); + + if (el < 2 && (mdcr_el2_tda || mdcr_el2_tdcc)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && ((env->cp15.mdcr_el3 & MDCR_TDA) || mdcr_el3_tdcc)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -681,7 +708,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { */ { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0, - .access = PL0_R, .accessfn = access_tda, + .access = PL0_R, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, /* * OSDTRRX_EL1/OSDTRTX_EL1 are used for save and restore of DBGDTRRX_EL0. @@ -689,11 +716,11 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { */ { .name = "OSDTRRX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 2, - .access = PL1_RW, .accessfn = access_tda, + .access = PL1_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "OSDTRTX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, - .access = PL1_RW, .accessfn = access_tda, + .access = PL1_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, /* * OSECCR_EL1 provides a mechanism for an operating system @@ -757,7 +784,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { */ { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, - .access = PL1_RW, .accessfn = access_tda, + .access = PL1_RW, .accessfn = access_tdcc, .type = ARM_CP_NOP }, /* * Dummy DBGCLAIM registers. From bb18151d8bd9bedc497ee9d4e8d81b39a4e5bbf6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 30 Jan 2023 18:24:59 +0000 Subject: [PATCH 420/814] target/arm: Enable FEAT_FGT on '-cpu max' Update the ID registers for TCG's '-cpu max' to report the presence of FEAT_FGT Fine-Grained Traps support. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Fuad Tabba Message-id: 20230130182459.3309057-24-peter.maydell@linaro.org Message-id: 20230127175507.2895013-24-peter.maydell@linaro.org --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index b87e064d9d..2062d71261 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -30,6 +30,7 @@ the following architecture extensions: - FEAT_ETS (Enhanced Translation Synchronization) - FEAT_EVT (Enhanced Virtualization Traps) - FEAT_FCMA (Floating-point complex number instructions) +- FEAT_FGT (Fine-Grained Traps) - FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FRINTTS (Floating-point to integer instructions) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 0e021960fb..4066950da1 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -1224,6 +1224,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */ + t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */ cpu->isar.id_aa64mmfr0 = t; t = cpu->isar.id_aa64mmfr1; From e2c649e5b5b334b0b2598f6213130dd71d1c0df8 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 13 Dec 2022 17:02:24 +0100 Subject: [PATCH 421/814] linux-user: Add missing MAP_HUGETLB and MAP_STACK flags in strace Add two missing mmap flags. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/strace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index 7bccb4f0c0..5027289bdd 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1057,6 +1057,8 @@ UNUSED static const struct flags mmap_flags[] = { #ifdef TARGET_MAP_UNINITIALIZED FLAG_TARGET(MAP_UNINITIALIZED), #endif + FLAG_TARGET(MAP_HUGETLB), + FLAG_TARGET(MAP_STACK), FLAG_END, }; From 6490d9aa62ef3cbbac2bf584fb0f3e737ab05e44 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 24 Jan 2023 10:10:19 -1000 Subject: [PATCH 422/814] linux-user: un-parent OBJECT(cpu) when closing thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reinstates commit 52f0c1607671293afcdb2acc2f83e9bccbfa74bb: While forcing the CPU to unrealize by hand does trigger the clean-up code we never fully free resources because refcount never reaches zero. This is because QOM automatically added objects without an explicit parent to /unattached/, incrementing the refcount. Instead of manually triggering unrealization just unparent the object and let the device machinery deal with that for us. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/866 Signed-off-by: Alex Bennée Reviewed-by: Laurent Vivier Message-Id: <20220811151413.3350684-2-alex.bennee@linaro.org> The original patch tickled a problem in target/arm, and was reverted. But that problem is fixed as of commit 3b07a936d3bf. Signed-off-by: Richard Henderson Message-Id: <20230124201019.3935934-1-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3e72bd333e..dbf51e500b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8756,7 +8756,13 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, if (CPU_NEXT(first_cpu)) { TaskState *ts = cpu->opaque; - object_property_set_bool(OBJECT(cpu), "realized", false, NULL); + if (ts->child_tidptr) { + put_user_u32(0, ts->child_tidptr); + do_sys_futex(g2h(cpu, ts->child_tidptr), + FUTEX_WAKE, INT_MAX, NULL, NULL, 0); + } + + object_unparent(OBJECT(cpu)); object_unref(OBJECT(cpu)); /* * At this point the CPU should be unrealized and removed @@ -8766,11 +8772,6 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, pthread_mutex_unlock(&clone_lock); - if (ts->child_tidptr) { - put_user_u32(0, ts->child_tidptr); - do_sys_futex(g2h(cpu, ts->child_tidptr), - FUTEX_WAKE, INT_MAX, NULL, NULL, 0); - } thread_cpu = NULL; g_free(ts); rcu_unregister_thread(); From d237b416b9499441b6833b91609ec840efd832b6 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 18 Jan 2023 04:01:44 -0500 Subject: [PATCH 423/814] linux-user: fix strace build w/out munlockall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mike Frysinger Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230118090144.31155-1-vapier@gentoo.org> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 5027289bdd..081fc87344 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1360,7 +1360,8 @@ UNUSED static const struct flags termios_lflags[] = { FLAG_END, }; -UNUSED static const struct flags mlockall_flags[] = { +#ifdef TARGET_NR_mlockall +static const struct flags mlockall_flags[] = { FLAG_TARGET(MCL_CURRENT), FLAG_TARGET(MCL_FUTURE), #ifdef MCL_ONFAULT @@ -1368,6 +1369,7 @@ UNUSED static const struct flags mlockall_flags[] = { #endif FLAG_END, }; +#endif /* IDs of the various system clocks */ #define TARGET_CLOCK_REALTIME 0 From d5dbbfe67e23ec35f7226c958bc3a76fd43ae10e Mon Sep 17 00:00:00 2001 From: Letu Ren Date: Sun, 1 Jan 2023 22:11:05 +0800 Subject: [PATCH 424/814] linux-user: add more netlink protocol constants Currently, qemu strace only prints four protocol contants. This patch adds others listed in "linux/netlink.h". Signed-off-by: Letu Ren Message-Id: <20230101141105.12024-1-fantasquex@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index 081fc87344..f38227ba5d 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -506,21 +506,69 @@ print_socket_protocol(int domain, int type, int protocol) case NETLINK_ROUTE: qemu_log("NETLINK_ROUTE"); break; + case NETLINK_UNUSED: + qemu_log("NETLINK_UNUSED"); + break; + case NETLINK_USERSOCK: + qemu_log("NETLINK_USERSOCK"); + break; + case NETLINK_FIREWALL: + qemu_log("NETLINK_FIREWALL"); + break; + case NETLINK_SOCK_DIAG: + qemu_log("NETLINK_SOCK_DIAG"); + break; + case NETLINK_NFLOG: + qemu_log("NETLINK_NFLOG"); + break; + case NETLINK_XFRM: + qemu_log("NETLINK_XFRM"); + break; + case NETLINK_SELINUX: + qemu_log("NETLINK_SELINUX"); + break; + case NETLINK_ISCSI: + qemu_log("NETLINK_ISCSI"); + break; case NETLINK_AUDIT: qemu_log("NETLINK_AUDIT"); break; + case NETLINK_FIB_LOOKUP: + qemu_log("NETLINK_FIB_LOOKUP"); + break; + case NETLINK_CONNECTOR: + qemu_log("NETLINK_CONNECTOR"); + break; case NETLINK_NETFILTER: qemu_log("NETLINK_NETFILTER"); break; + case NETLINK_IP6_FW: + qemu_log("NETLINK_IP6_FW"); + break; + case NETLINK_DNRTMSG: + qemu_log("NETLINK_DNRTMSG"); + break; case NETLINK_KOBJECT_UEVENT: qemu_log("NETLINK_KOBJECT_UEVENT"); break; + case NETLINK_GENERIC: + qemu_log("NETLINK_GENERIC"); + break; + case NETLINK_SCSITRANSPORT: + qemu_log("NETLINK_SCSITRANSPORT"); + break; + case NETLINK_ECRYPTFS: + qemu_log("NETLINK_ECRYPTFS"); + break; case NETLINK_RDMA: qemu_log("NETLINK_RDMA"); break; case NETLINK_CRYPTO: qemu_log("NETLINK_CRYPTO"); break; + case NETLINK_SMC: + qemu_log("NETLINK_SMC"); + break; default: qemu_log("%d", protocol); break; From 9f0246539ae84a5e21efd1cc4516fc343f08115a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 10 Jan 2023 12:49:00 -0500 Subject: [PATCH 425/814] Revert "linux-user: add more compat ioctl definitions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c5495f4ecb0cdaaf2e9dddeb48f1689cdb520ca0. glibc has fixed (in 2.36.9000-40-g774058d729) the problem that caused a clash when both sys/mount.h annd linux/mount.h are included, and backported this to the 2.36 stable release too: https://sourceware.org/glibc/wiki/Release/2.36#Usage_of_.3Clinux.2Fmount.h.3E_and_.3Csys.2Fmount.h.3E It is saner for QEMU to remove the workaround it applied for glibc 2.36 and expect distros to ship the 2.36 maint release with the fix. This avoids needing to add a further workaround to QEMU to deal with the fact that linux/brtfs.h now also pulls in linux/mount.h via linux/fs.h since Linux 6.1 Signed-off-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Message-Id: <20230110174901.2580297-2-berrange@redhat.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dbf51e500b..b88f8ee96f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -111,31 +111,6 @@ #define FS_IOC32_SETFLAGS _IOW('f', 2, int) #define FS_IOC32_GETVERSION _IOR('v', 1, int) #define FS_IOC32_SETVERSION _IOW('v', 2, int) - -#define BLKGETSIZE64 _IOR(0x12,114,size_t) -#define BLKDISCARD _IO(0x12,119) -#define BLKIOMIN _IO(0x12,120) -#define BLKIOOPT _IO(0x12,121) -#define BLKALIGNOFF _IO(0x12,122) -#define BLKPBSZGET _IO(0x12,123) -#define BLKDISCARDZEROES _IO(0x12,124) -#define BLKSECDISCARD _IO(0x12,125) -#define BLKROTATIONAL _IO(0x12,126) -#define BLKZEROOUT _IO(0x12,127) - -#define FIBMAP _IO(0x00,1) -#define FIGETBSZ _IO(0x00,2) - -struct file_clone_range { - __s64 src_fd; - __u64 src_offset; - __u64 src_length; - __u64 dest_offset; -}; - -#define FICLONE _IOW(0x94, 9, int) -#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) - #else #include #endif From 6003159ce18faad4e1bc7bf9c85669019cd4950e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 10 Jan 2023 12:49:01 -0500 Subject: [PATCH 426/814] Revert "linux-user: fix compat with glibc >= 2.36 sys/mount.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3cd3df2a9584e6f753bb62a0028bd67124ab5532. glibc has fixed (in 2.36.9000-40-g774058d729) the problem that caused a clash when both sys/mount.h annd linux/mount.h are included, and backported this to the 2.36 stable release too: https://sourceware.org/glibc/wiki/Release/2.36#Usage_of_.3Clinux.2Fmount.h.3E_and_.3Csys.2Fmount.h.3E It is saner for QEMU to remove the workaround it applied for glibc 2.36 and expect distros to ship the 2.36 maint release with the fix. This avoids needing to add a further workaround to QEMU to deal with the fact that linux/brtfs.h now also pulls in linux/mount.h via linux/fs.h since Linux 6.1 Signed-off-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Message-Id: <20230110174901.2580297-3-berrange@redhat.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 18 ------------------ meson.build | 2 -- 2 files changed, 20 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b88f8ee96f..210db5f0be 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -95,25 +95,7 @@ #include #include #include - -#ifdef HAVE_SYS_MOUNT_FSCONFIG -/* - * glibc >= 2.36 linux/mount.h conflicts with sys/mount.h, - * which in turn prevents use of linux/fs.h. So we have to - * define the constants ourselves for now. - */ -#define FS_IOC_GETFLAGS _IOR('f', 1, long) -#define FS_IOC_SETFLAGS _IOW('f', 2, long) -#define FS_IOC_GETVERSION _IOR('v', 1, long) -#define FS_IOC_SETVERSION _IOW('v', 2, long) -#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) -#define FS_IOC32_GETFLAGS _IOR('f', 1, int) -#define FS_IOC32_SETFLAGS _IOW('f', 2, int) -#define FS_IOC32_GETVERSION _IOR('v', 1, int) -#define FS_IOC32_SETVERSION _IOW('v', 2, int) -#else #include -#endif #include #if defined(CONFIG_FIEMAP) #include diff --git a/meson.build b/meson.build index 6d3b665629..cccd19f864 100644 --- a/meson.build +++ b/meson.build @@ -2046,8 +2046,6 @@ config_host_data.set('HAVE_OPTRESET', cc.has_header_symbol('getopt.h', 'optreset')) config_host_data.set('HAVE_IPPROTO_MPTCP', cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP')) -config_host_data.set('HAVE_SYS_MOUNT_FSCONFIG', - cc.has_header_symbol('sys/mount.h', 'FSCONFIG_SET_FLAG')) # has_member config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', From dfd8c5e9b383c36ed6d9559afe331a38967998a8 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 15 Jan 2023 12:35:17 +0100 Subject: [PATCH 427/814] linux-user: Add strace output for clock_getres_time64() and futex_time64() Add the two syscalls to strace output to avoid "Unknown syscall" message. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20230115113517.25143-1-deller@gmx.de> Signed-off-by: Laurent Vivier --- linux-user/strace.list | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/strace.list b/linux-user/strace.list index bb21c05414..64db8e6b84 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -86,6 +86,9 @@ { TARGET_NR_clock_getres, "clock_getres" , NULL, print_clock_getres, print_syscall_ret_clock_getres }, #endif +#ifdef TARGET_NR_clock_getres_time64 +{ TARGET_NR_clock_getres_time64, "clock_getres_time64" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_clock_gettime { TARGET_NR_clock_gettime, "clock_gettime" , NULL, print_clock_gettime, print_syscall_ret_clock_gettime }, @@ -275,6 +278,9 @@ #ifdef TARGET_NR_futex { TARGET_NR_futex, "futex" , NULL, print_futex, NULL }, #endif +#ifdef TARGET_NR_futex_time64 +{ TARGET_NR_futex_time64, "futex_time64" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_futimesat { TARGET_NR_futimesat, "futimesat" , NULL, print_futimesat, NULL }, #endif From 6a848b522e189824f25bcfe9ec856c1f85e93fa3 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 15 Jan 2023 22:00:57 +0100 Subject: [PATCH 428/814] linux-user: Improve strace output of getgroups() and setgroups() Make the strace look nicer for those syscalls. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20230115210057.445132-1-deller@gmx.de> Signed-off-by: Laurent Vivier --- linux-user/strace.list | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/strace.list b/linux-user/strace.list index 64db8e6b84..cf291d02ed 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -321,10 +321,10 @@ { TARGET_NR_getgid32, "getgid32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getgroups -{ TARGET_NR_getgroups, "getgroups" , NULL, NULL, NULL }, +{ TARGET_NR_getgroups, "getgroups" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_getgroups32 -{ TARGET_NR_getgroups32, "getgroups32" , NULL, NULL, NULL }, +{ TARGET_NR_getgroups32, "getgroups32" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_gethostname { TARGET_NR_gethostname, "gethostname" , NULL, NULL, NULL }, @@ -1304,10 +1304,10 @@ { TARGET_NR_setgid32, "setgid32" , "%s(%u)", NULL, NULL }, #endif #ifdef TARGET_NR_setgroups -{ TARGET_NR_setgroups, "setgroups" , NULL, NULL, NULL }, +{ TARGET_NR_setgroups, "setgroups" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_setgroups32 -{ TARGET_NR_setgroups32, "setgroups32" , NULL, NULL, NULL }, +{ TARGET_NR_setgroups32, "setgroups32" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sethae { TARGET_NR_sethae, "sethae" , NULL, NULL, NULL }, From 95fc5ed4a86b0d173bf55daf32e1697d11062648 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 28 Jan 2023 19:46:25 -0500 Subject: [PATCH 429/814] linux-user: move target_flat.h to target subdirs This makes target_flat.h behave like every other target_xxx.h header. It also makes it actually work -- while the current header says adding a header to the target subdir overrides the common one, it doesn't. This is for two reasons: * meson.build adds -Ilinux-user before -Ilinux-user/$arch * the compiler search path for "target_flat.h" looks in the same dir as the source file before searching -I paths. This can be seen with the xtensa port -- the subdir settings aren't used which breaks stack setup. Move it to the generic/ subdir and add include stubs like every other target_xxx.h header is handled. Signed-off-by: Mike Frysinger Reviewed-by: Richard Henderson Message-Id: <20230129004625.11228-1-vapier@gentoo.org> Signed-off-by: Laurent Vivier --- linux-user/aarch64/target_flat.h | 1 + linux-user/arm/target_flat.h | 1 + linux-user/{ => generic}/target_flat.h | 0 linux-user/m68k/target_flat.h | 1 + linux-user/microblaze/target_flat.h | 1 + linux-user/sh4/target_flat.h | 1 + 6 files changed, 5 insertions(+) create mode 100644 linux-user/aarch64/target_flat.h create mode 100644 linux-user/arm/target_flat.h rename linux-user/{ => generic}/target_flat.h (100%) create mode 100644 linux-user/m68k/target_flat.h create mode 100644 linux-user/microblaze/target_flat.h create mode 100644 linux-user/sh4/target_flat.h diff --git a/linux-user/aarch64/target_flat.h b/linux-user/aarch64/target_flat.h new file mode 100644 index 0000000000..bc83224cea --- /dev/null +++ b/linux-user/aarch64/target_flat.h @@ -0,0 +1 @@ +#include "../generic/target_flat.h" diff --git a/linux-user/arm/target_flat.h b/linux-user/arm/target_flat.h new file mode 100644 index 0000000000..bc83224cea --- /dev/null +++ b/linux-user/arm/target_flat.h @@ -0,0 +1 @@ +#include "../generic/target_flat.h" diff --git a/linux-user/target_flat.h b/linux-user/generic/target_flat.h similarity index 100% rename from linux-user/target_flat.h rename to linux-user/generic/target_flat.h diff --git a/linux-user/m68k/target_flat.h b/linux-user/m68k/target_flat.h new file mode 100644 index 0000000000..bc83224cea --- /dev/null +++ b/linux-user/m68k/target_flat.h @@ -0,0 +1 @@ +#include "../generic/target_flat.h" diff --git a/linux-user/microblaze/target_flat.h b/linux-user/microblaze/target_flat.h new file mode 100644 index 0000000000..bc83224cea --- /dev/null +++ b/linux-user/microblaze/target_flat.h @@ -0,0 +1 @@ +#include "../generic/target_flat.h" diff --git a/linux-user/sh4/target_flat.h b/linux-user/sh4/target_flat.h new file mode 100644 index 0000000000..bc83224cea --- /dev/null +++ b/linux-user/sh4/target_flat.h @@ -0,0 +1 @@ +#include "../generic/target_flat.h" From cb88b7c214511736fa3bc1d9e57b23efcc61d8ab Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 27 Jan 2023 21:25:27 +0100 Subject: [PATCH 430/814] linux-user: Fix SO_ERROR return code of getsockopt() Add translation for the host error return code of: getsockopt(19, SOL_SOCKET, SO_ERROR, [ECONNREFUSED], [4]) = 0 This fixes the testsuite of the cockpit debian package with a hppa-linux guest on a x86-64 host. Signed-off-by: Helge Deller Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 210db5f0be..1c42df6518 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2758,8 +2758,13 @@ get_timeout: ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; - if (optname == SO_TYPE) { + switch (optname) { + case SO_TYPE: val = host_to_target_sock_type(val); + break; + case SO_ERROR: + val = host_to_target_errno(val); + break; } if (len > lv) len = lv; From e0174afeea23e56765db56fbbe465ed1fcbdd07a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 27 Jan 2023 21:10:49 +0100 Subject: [PATCH 431/814] linux-user: Fix /proc/cpuinfo output for hppa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hppa architectures provides an own output for the emulated /proc/cpuinfo file. Some userspace applications count (even if that's not the recommended way) the number of lines which start with "processor:" and assume that this number then reflects the number of online CPUs. Since those 3 architectures don't provide any such line, applications may assume "0" CPUs. One such issue can be seen in debian bug report: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1024653 Avoid such issues by adding a "processor:" line for each of the online CPUs. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1c42df6518..55d53b344b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8232,11 +8232,17 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd) #if defined(TARGET_HPPA) static int open_cpuinfo(CPUArchState *cpu_env, int fd) { - dprintf(fd, "cpu family\t: PA-RISC 1.1e\n"); - dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n"); - dprintf(fd, "capabilities\t: os32\n"); - dprintf(fd, "model\t\t: 9000/778/B160L\n"); - dprintf(fd, "model name\t: Merlin L2 160 QEMU (9000/778/B160L)\n"); + int i, num_cpus; + + num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + for (i = 0; i < num_cpus; i++) { + dprintf(fd, "processor\t: %d\n", i); + dprintf(fd, "cpu family\t: PA-RISC 1.1e\n"); + dprintf(fd, "cpu\t\t: PA7300LC (PCX-L2)\n"); + dprintf(fd, "capabilities\t: os32\n"); + dprintf(fd, "model\t\t: 9000/778/B160L - " + "Merlin L2 160 QEMU (9000/778/B160L)\n\n"); + } return 0; } #endif From ab6c497e7eb8a9dca45978e5118f5c67bb74ab62 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 27 Jan 2023 21:18:58 +0100 Subject: [PATCH 432/814] linux-user: Improve strace output of personality() and sysinfo() Make the strace look nicer for those two syscalls. Signed-off-by: Helge Deller Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/strace.list | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.list b/linux-user/strace.list index cf291d02ed..3a1f61803a 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1049,7 +1049,8 @@ { TARGET_NR_perfctr, "perfctr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_personality -{ TARGET_NR_personality, "personality" , NULL, NULL, NULL }, +{ TARGET_NR_personality, "personality" , "%s(0x"TARGET_ABI_FMT_lx")", NULL, + print_syscall_ret_addr }, #endif #ifdef TARGET_NR_pipe { TARGET_NR_pipe, "pipe" , NULL, NULL, NULL }, @@ -1504,7 +1505,7 @@ { TARGET_NR_sysfs, "sysfs" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_sysinfo -{ TARGET_NR_sysinfo, "sysinfo" , NULL, NULL, NULL }, +{ TARGET_NR_sysinfo, "sysinfo" , "%s(%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sys_kexec_load { TARGET_NR_sys_kexec_load, "sys_kexec_load" , NULL, NULL, NULL }, From 4530deb1fe81152ae2384a56eb7edb5467f894fa Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 13 Dec 2022 18:03:09 +0100 Subject: [PATCH 433/814] linux-user: Add emulation for MADV_WIPEONFORK and MADV_KEEPONFORK in madvise() Both parameters have a different value on the parisc platform, so first translate the target value into a host value for usage in the native madvise() syscall. Those parameters are often used by security sensitive applications (e.g. tor browser, boringssl, ...) which expect the call to return a proper return code on failure, so return -EINVAL if qemu fails to forward the syscall to the host OS. While touching this code, enhance the comments about MADV_DONTNEED. Tested with testcase of tor browser when running hppa-linux guest on x86-64 host. Signed-off-by: Helge Deller Acked-by: Ilya Leoshkevich Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/mmap.c | 56 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 10f5079331..28135c9e6a 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -857,7 +857,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, return new_addr; } -static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end) +static bool can_passthrough_madvise(abi_ulong start, abi_ulong end) { ulong addr; @@ -901,23 +901,53 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) return -TARGET_EINVAL; } + /* Translate for some architectures which have different MADV_xxx values */ + switch (advice) { + case TARGET_MADV_DONTNEED: /* alpha */ + advice = MADV_DONTNEED; + break; + case TARGET_MADV_WIPEONFORK: /* parisc */ + advice = MADV_WIPEONFORK; + break; + case TARGET_MADV_KEEPONFORK: /* parisc */ + advice = MADV_KEEPONFORK; + break; + /* we do not care about the other MADV_xxx values yet */ + } + /* - * A straight passthrough may not be safe because qemu sometimes turns - * private file-backed mappings into anonymous mappings. + * Most advice values are hints, so ignoring and returning success is ok. * - * This is a hint, so ignoring and returning success is ok. + * However, some advice values such as MADV_DONTNEED, MADV_WIPEONFORK and + * MADV_KEEPONFORK are not hints and need to be emulated. * - * This breaks MADV_DONTNEED, completely implementing which is quite - * complicated. However, there is one low-hanging fruit: mappings that are - * known to have the same semantics in the host and the guest. In this case - * passthrough is safe, so do it. + * A straight passthrough for those may not be safe because qemu sometimes + * turns private file-backed mappings into anonymous mappings. + * can_passthrough_madvise() helps to check if a passthrough is possible by + * comparing mappings that are known to have the same semantics in the host + * and the guest. In this case passthrough is safe. + * + * We pass through MADV_WIPEONFORK and MADV_KEEPONFORK if possible and + * return failure if not. + * + * MADV_DONTNEED is passed through as well, if possible. + * If passthrough isn't possible, we nevertheless (wrongly!) return + * success, which is broken but some userspace programs fail to work + * otherwise. Completely implementing such emulation is quite complicated + * though. */ mmap_lock(); - if (advice == TARGET_MADV_DONTNEED && - can_passthrough_madv_dontneed(start, end)) { - ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED)); - if (ret == 0) { - page_reset_target_data(start, start + len); + switch (advice) { + case MADV_WIPEONFORK: + case MADV_KEEPONFORK: + ret = -EINVAL; + /* fall through */ + case MADV_DONTNEED: + if (can_passthrough_madvise(start, end)) { + ret = get_errno(madvise(g2h_untagged(start), len, advice)); + if ((advice == MADV_DONTNEED) && (ret == 0)) { + page_reset_target_data(start, start + len); + } } } mmap_unlock(); From 7020e2fd9e1d23b16c8ef86a217a865f5ec66cbe Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 30 Jan 2023 23:20:53 +0100 Subject: [PATCH 434/814] linux-user: Show 4th argument of rt_sigprocmask() in strace Add output for the missing 4th parameter (size_t sigsetsize). Signed-off-by: Helge Deller Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/strace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index f38227ba5d..340010661c 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -3224,7 +3224,8 @@ print_rt_sigprocmask(CPUArchState *cpu_env, const struct syscallname *name, } qemu_log("%s,", how); print_pointer(arg1, 0); - print_pointer(arg2, 1); + print_pointer(arg2, 0); + print_raw_param("%u", arg3, 1); print_syscall_epilogue(name); } #endif From 93cf7e6c4abdbc5e678088cee4e08f615ad39766 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 12 Dec 2022 19:01:32 +0100 Subject: [PATCH 435/814] linux-user: Enhance strace output for various syscalls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add appropriate strace printf formats for various Linux syscalls. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Laurent Vivier --- linux-user/strace.list | 43 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/linux-user/strace.list b/linux-user/strace.list index 3a1f61803a..d8acbeec60 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -343,7 +343,7 @@ { TARGET_NR_getpagesize, "getpagesize" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getpeername -{ TARGET_NR_getpeername, "getpeername" , NULL, NULL, NULL }, +{ TARGET_NR_getpeername, "getpeername" , "%s(%d,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_getpgid { TARGET_NR_getpgid, "getpgid" , "%s(%u)", NULL, NULL }, @@ -367,19 +367,19 @@ { TARGET_NR_getrandom, "getrandom", "%s(%p,%u,%u)", NULL, NULL }, #endif #ifdef TARGET_NR_getresgid -{ TARGET_NR_getresgid, "getresgid" , NULL, NULL, NULL }, +{ TARGET_NR_getresgid, "getresgid" , "%s(%p,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_getresgid32 { TARGET_NR_getresgid32, "getresgid32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getresuid -{ TARGET_NR_getresuid, "getresuid" , NULL, NULL, NULL }, +{ TARGET_NR_getresuid, "getresuid" , "%s(%p,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_getresuid32 { TARGET_NR_getresuid32, "getresuid32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getrlimit -{ TARGET_NR_getrlimit, "getrlimit" , NULL, NULL, NULL }, +{ TARGET_NR_getrlimit, "getrlimit" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_get_robust_list { TARGET_NR_get_robust_list, "get_robust_list" , NULL, NULL, NULL }, @@ -391,10 +391,10 @@ { TARGET_NR_getsid, "getsid" , "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_getsockname -{ TARGET_NR_getsockname, "getsockname" , NULL, NULL, NULL }, +{ TARGET_NR_getsockname, "getsockname" , "%s(%d,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_getsockopt -{ TARGET_NR_getsockopt, "getsockopt" , NULL, NULL, NULL }, +{ TARGET_NR_getsockopt, "getsockopt" , "%s(%d,%d,%d,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_get_thread_area #if defined(TARGET_I386) && defined(TARGET_ABI32) @@ -1059,10 +1059,10 @@ { TARGET_NR_pivot_root, "pivot_root" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_poll -{ TARGET_NR_poll, "poll" , NULL, NULL, NULL }, +{ TARGET_NR_poll, "poll" , "%s(%p,%u,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_ppoll -{ TARGET_NR_ppoll, "ppoll" , NULL, NULL, NULL }, +{ TARGET_NR_ppoll, "ppoll" , "%s(%p,%u,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_prctl { TARGET_NR_prctl, "prctl" , NULL, NULL, NULL }, @@ -1131,7 +1131,7 @@ { TARGET_NR_reboot, "reboot" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_recv -{ TARGET_NR_recv, "recv" , NULL, NULL, NULL }, +{ TARGET_NR_recv, "recv" , "%s(%d,%p,%u,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_recvfrom { TARGET_NR_recvfrom, "recvfrom" , NULL, NULL, NULL }, @@ -1191,7 +1191,7 @@ { TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, print_rt_sigqueueinfo, NULL }, #endif #ifdef TARGET_NR_rt_sigreturn -{ TARGET_NR_rt_sigreturn, "rt_sigreturn" , NULL, NULL, NULL }, +{ TARGET_NR_rt_sigreturn, "rt_sigreturn" , "%s(%p)", NULL, NULL }, #endif #ifdef TARGET_NR_rt_sigsuspend { TARGET_NR_rt_sigsuspend, "rt_sigsuspend" , NULL, NULL, NULL }, @@ -1203,16 +1203,19 @@ { TARGET_NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo" , NULL, print_rt_tgsigqueueinfo, NULL }, #endif #ifdef TARGET_NR_sched_getaffinity -{ TARGET_NR_sched_getaffinity, "sched_getaffinity" , NULL, NULL, NULL }, +{ TARGET_NR_sched_getaffinity, "sched_getaffinity" , "%s(%d,%u,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sched_get_affinity { TARGET_NR_sched_get_affinity, "sched_get_affinity" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_sched_getattr -{ TARGET_NR_sched_getattr, "sched_getattr" , NULL, NULL, NULL }, +{ TARGET_NR_sched_getattr, "sched_getattr" , "%s(%d,%p,%u,%u)", NULL, NULL }, +#endif +#ifdef TARGET_NR_sched_setattr +{ TARGET_NR_sched_setattr, "sched_setattr" , "%s(%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sched_getparam -{ TARGET_NR_sched_getparam, "sched_getparam" , NULL, NULL, NULL }, +{ TARGET_NR_sched_getparam, "sched_getparam" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sched_get_priority_max { TARGET_NR_sched_get_priority_max, "sched_get_priority_max" , NULL, NULL, NULL }, @@ -1227,7 +1230,7 @@ { TARGET_NR_sched_rr_get_interval, "sched_rr_get_interval" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_sched_setaffinity -{ TARGET_NR_sched_setaffinity, "sched_setaffinity" , NULL, NULL, NULL }, +{ TARGET_NR_sched_setaffinity, "sched_setaffinity" , "%s(%d,%u,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_sched_setatt { TARGET_NR_sched_setatt, "sched_setatt" , NULL, NULL, NULL }, @@ -1360,23 +1363,23 @@ { TARGET_NR_setreuid32, "setreuid32" , "%s(%u,%u)", NULL, NULL }, #endif #ifdef TARGET_NR_setrlimit -{ TARGET_NR_setrlimit, "setrlimit" , NULL, NULL, NULL }, +{ TARGET_NR_setrlimit, "setrlimit" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_set_robust_list -{ TARGET_NR_set_robust_list, "set_robust_list" , NULL, NULL, NULL }, +{ TARGET_NR_set_robust_list, "set_robust_list" , "%s(%p,%u)", NULL, NULL }, #endif #ifdef TARGET_NR_setsid { TARGET_NR_setsid, "setsid" , "%s()", NULL, NULL }, #endif #ifdef TARGET_NR_setsockopt -{ TARGET_NR_setsockopt, "setsockopt" , NULL, NULL, NULL }, +{ TARGET_NR_setsockopt, "setsockopt" , "%s(%d,%d,%d,%p,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_set_thread_area { TARGET_NR_set_thread_area, "set_thread_area", "%s(0x"TARGET_ABI_FMT_lx")", NULL, NULL }, #endif #ifdef TARGET_NR_set_tid_address -{ TARGET_NR_set_tid_address, "set_tid_address" , NULL, NULL, NULL }, +{ TARGET_NR_set_tid_address, "set_tid_address" , "%s(%p)", NULL, NULL }, #endif #ifdef TARGET_NR_settimeofday { TARGET_NR_settimeofday, "settimeofday" , NULL, print_settimeofday, NULL }, @@ -1655,7 +1658,7 @@ { TARGET_NR_vserver, "vserver" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_wait4 -{ TARGET_NR_wait4, "wait4" , NULL, NULL, NULL }, +{ TARGET_NR_wait4, "wait4" , "%s(%d,%p,%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_waitid { TARGET_NR_waitid, "waitid" , "%s(%#x,%d,%p,%#x)", NULL, NULL }, @@ -1679,7 +1682,7 @@ { TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL }, #endif #ifdef TARGET_NR_pipe2 -{ TARGET_NR_pipe2, "pipe2", NULL, NULL, NULL }, +{ TARGET_NR_pipe2, "pipe2", "%s(%p,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_pidfd_open { TARGET_NR_pidfd_open, "pidfd_open", "%s(%d,%u)", NULL, NULL }, From 27404b6c15c1cddae54e1044c8da815eade109fa Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 12 Dec 2022 18:34:15 +0100 Subject: [PATCH 436/814] linux-user: Implement SOL_ALG encryption support Add suport to handle SOL_ALG packets via sendmsg() and recvmsg(). This allows emulated userspace to use encryption functionality. Tested with the debian ell package with hppa guest on x86_64 host. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20221212173416.90590-1-deller@gmx.de> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 55d53b344b..a0d2beddaa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1829,6 +1829,14 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, __get_user(cred->pid, &target_cred->pid); __get_user(cred->uid, &target_cred->uid); __get_user(cred->gid, &target_cred->gid); + } else if (cmsg->cmsg_level == SOL_ALG) { + uint32_t *dst = (uint32_t *)data; + + memcpy(dst, target_data, len); + /* fix endianess of first 32-bit word */ + if (len >= sizeof(uint32_t)) { + *dst = tswap32(*dst); + } } else { qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); From 3f0744f98b07c6fd2ce9d5840726d0915b2ae7c1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 12 Dec 2022 18:34:16 +0100 Subject: [PATCH 437/814] linux-user: Allow sendmsg() without IOV Applications do call sendmsg() without any IOV, e.g.: sendmsg(4, {msg_name=NULL, msg_namelen=0, msg_iov=NULL, msg_iovlen=0, msg_control=[{cmsg_len=36, cmsg_level=SOL_ALG, cmsg_type=0x2}], msg_controllen=40, msg_flags=0}, MSG_MORE) = 0 sendmsg(4, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="The quick brown fox jumps over t"..., iov_len=183}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_ALG, cmsg_type=0x3}], msg_controllen=24, msg_flags=0}, 0) = 183 The function do_sendrecvmsg_locked() is used for sndmsg() and recvmsg() and calls lock_iovec() to lock the IOV into memory. For the first sendmsg() above it returns NULL and thus wrongly skips the call the host sendmsg() syscall, which will break the calling application. Fix this issue by: - allowing sendmsg() even with empty IOV - skip recvmsg() if IOV is NULL - skip both if the return code of do_sendrecvmsg_locked() != 0, which indicates some failure like EFAULT on the IOV Tested with the debian "ell" package with hppa guest on x86_64 host. Signed-off-by: Helge Deller Reviewed-by: Laurent Vivier Message-Id: <20221212173416.90590-2-deller@gmx.de> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a0d2beddaa..1e868e9b0e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3293,7 +3293,10 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, target_vec, count, send); if (vec == NULL) { ret = -host_to_target_errno(errno); - goto out2; + /* allow sending packet without any iov, e.g. with MSG_MORE flag */ + if (!send || ret) { + goto out2; + } } msg.msg_iovlen = count; msg.msg_iov = vec; @@ -3345,7 +3348,9 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, } out: - unlock_iovec(vec, target_vec, count, !send); + if (vec) { + unlock_iovec(vec, target_vec, count, !send); + } out2: return ret; } From 15b7646c7d0d17f41b78f3af5adb21a2e4e45a93 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:15 +0100 Subject: [PATCH 438/814] monitor: Drop unnecessary includes Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-2-armbru@redhat.com> Reviewed-by: Stefan Berger --- monitor/hmp-cmds.c | 4 ---- monitor/hmp.c | 2 -- monitor/misc.c | 14 ++------------ monitor/qmp-cmds-control.c | 1 - monitor/qmp-cmds.c | 8 -------- 5 files changed, 2 insertions(+), 27 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 1dba973092..de1a96d48c 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -18,17 +18,14 @@ #include "net/net.h" #include "net/eth.h" #include "chardev/char.h" -#include "sysemu/block-backend.h" #include "sysemu/runstate.h" #include "qemu/config-file.h" #include "qemu/option.h" -#include "qemu/timer.h" #include "qemu/sockets.h" #include "qemu/help_option.h" #include "monitor/monitor.h" #include "qapi/error.h" #include "qapi/clone-visitor.h" -#include "qapi/opts-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-char.h" @@ -42,7 +39,6 @@ #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" #include "qapi/qapi-commands-virtio.h" -#include "qapi/qapi-visit-virtio.h" #include "qapi/qapi-visit-net.h" #include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qdict.h" diff --git a/monitor/hmp.c b/monitor/hmp.c index 43fd69f984..e5d914b1f5 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -27,7 +27,6 @@ #include "hw/qdev-core.h" #include "monitor-internal.h" #include "monitor/hmp.h" -#include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qnum.h" #include "qemu/config-file.h" @@ -37,7 +36,6 @@ #include "qemu/option.h" #include "qemu/units.h" #include "sysemu/block-backend.h" -#include "sysemu/runstate.h" #include "trace.h" static void monitor_command_cb(void *opaque, const char *cmdline, diff --git a/monitor/misc.c b/monitor/misc.c index 053af4045e..6fc8bfef13 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -25,27 +25,20 @@ #include "qemu/osdep.h" #include "monitor-internal.h" #include "monitor/qdev.h" -#include "hw/pci/pci.h" -#include "sysemu/watchdog.h" #include "exec/gdbstub.h" #include "net/net.h" #include "net/slirp.h" #include "ui/qemu-spice.h" -#include "qemu/config-file.h" #include "qemu/ctype.h" #include "audio/audio.h" #include "disas/disas.h" -#include "qemu/timer.h" #include "qemu/log.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" -#include "authz/list.h" -#include "qapi/util.h" #include "sysemu/sysemu.h" #include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qapi/qmp/qstring.h" #include "qom/object_interfaces.h" #include "trace/control.h" #include "monitor/hmp-target.h" @@ -53,10 +46,8 @@ #ifdef CONFIG_TRACE_SIMPLE #include "trace/simple.h" #endif -#include "exec/memory.h" -#include "exec/exec-all.h" -#include "qemu/option.h" -#include "qemu/thread.h" +#include "exec/address-spaces.h" +#include "exec/ioport.h" #include "block/qapi.h" #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-char.h" @@ -69,7 +60,6 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-init-commands.h" #include "qapi/error.h" -#include "qapi/qmp-event.h" #include "qemu/cutils.h" #if defined(TARGET_S390X) diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c index 6e581713a3..f21506efa5 100644 --- a/monitor/qmp-cmds-control.c +++ b/monitor/qmp-cmds-control.c @@ -30,7 +30,6 @@ #include "qapi/error.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-introspect.h" -#include "qapi/qapi-emit-events.h" #include "qapi/qapi-introspect.h" #include "qapi/qapi-visit-introspect.h" #include "qapi/qobject-input-visitor.h" diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index bf22a8c5a6..743849c0b5 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -14,29 +14,21 @@ */ #include "qemu/osdep.h" -#include "block/blockjob.h" -#include "qemu/cutils.h" -#include "qemu/option.h" #include "monitor/monitor.h" #include "monitor/qmp-helpers.h" #include "sysemu/sysemu.h" -#include "qemu/config-file.h" -#include "qemu/uuid.h" #include "chardev/char.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "sysemu/runstate-action.h" -#include "sysemu/blockdev.h" #include "sysemu/block-backend.h" #include "qapi/error.h" #include "qapi/qapi-commands-acpi.h" -#include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-stats.h" #include "qapi/type-helpers.h" -#include "exec/ramlist.h" #include "hw/mem/memory-device.h" #include "hw/acpi/acpi_dev_interface.h" #include "hw/intc/intc.h" From 98b5362bdd53188d0bf1754267f49580cde9dde1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:16 +0100 Subject: [PATCH 439/814] audio: Move HMP commands from monitor/ to audio/ This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Overall Audio backends". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-3-armbru@redhat.com> --- audio/audio-hmp-cmds.c | 83 ++++++++++++++++++++++++++++++++++++++++++ audio/meson.build | 1 + include/monitor/hmp.h | 3 ++ monitor/misc.c | 56 ---------------------------- 4 files changed, 87 insertions(+), 56 deletions(-) create mode 100644 audio/audio-hmp-cmds.c diff --git a/audio/audio-hmp-cmds.c b/audio/audio-hmp-cmds.c new file mode 100644 index 0000000000..1237ce9e75 --- /dev/null +++ b/audio/audio-hmp-cmds.c @@ -0,0 +1,83 @@ +/* + * HMP commands related to audio backends + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "audio/audio.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/qmp/qdict.h" + +static QLIST_HEAD (capture_list_head, CaptureState) capture_head; + +void hmp_info_capture(Monitor *mon, const QDict *qdict) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + monitor_printf(mon, "[%d]: ", i); + s->ops.info (s->opaque); + } +} + +void hmp_stopcapture(Monitor *mon, const QDict *qdict) +{ + int i; + int n = qdict_get_int(qdict, "n"); + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + if (i == n) { + s->ops.destroy (s->opaque); + QLIST_REMOVE (s, entries); + g_free (s); + return; + } + } +} + +void hmp_wavcapture(Monitor *mon, const QDict *qdict) +{ + const char *path = qdict_get_str(qdict, "path"); + int freq = qdict_get_try_int(qdict, "freq", 44100); + int bits = qdict_get_try_int(qdict, "bits", 16); + int nchannels = qdict_get_try_int(qdict, "nchannels", 2); + const char *audiodev = qdict_get_str(qdict, "audiodev"); + CaptureState *s; + AudioState *as = audio_state_by_name(audiodev); + + if (!as) { + monitor_printf(mon, "Audiodev '%s' not found\n", audiodev); + return; + } + + s = g_malloc0 (sizeof (*s)); + + if (wav_start_capture(as, s, path, freq, bits, nchannels)) { + monitor_printf(mon, "Failed to add wave capture\n"); + g_free (s); + return; + } + QLIST_INSERT_HEAD (&capture_head, s, entries); +} diff --git a/audio/meson.build b/audio/meson.build index 34aed78342..0722224ba9 100644 --- a/audio/meson.build +++ b/audio/meson.build @@ -1,5 +1,6 @@ softmmu_ss.add([spice_headers, files('audio.c')]) softmmu_ss.add(files( + 'audio-hmp-cmds.c', 'audio_legacy.c', 'mixeng.c', 'noaudio.c', diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 1b3bdcb446..c25bec1863 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -151,5 +151,8 @@ void hmp_human_readable_text_helper(Monitor *mon, HumanReadableText *(*qmp_handler)(Error **)); void hmp_info_stats(Monitor *mon, const QDict *qdict); void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); +void hmp_info_capture(Monitor *mon, const QDict *qdict); +void hmp_stopcapture(Monitor *mon, const QDict *qdict); +void hmp_wavcapture(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor/misc.c b/monitor/misc.c index 6fc8bfef13..80d5527774 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -30,7 +30,6 @@ #include "net/slirp.h" #include "ui/qemu-spice.h" #include "qemu/ctype.h" -#include "audio/audio.h" #include "disas/disas.h" #include "qemu/log.h" #include "sysemu/hw_accel.h" @@ -892,61 +891,6 @@ static void hmp_info_mtree(Monitor *mon, const QDict *qdict) mtree_info(flatview, dispatch_tree, owner, disabled); } -/* Capture support */ -static QLIST_HEAD (capture_list_head, CaptureState) capture_head; - -static void hmp_info_capture(Monitor *mon, const QDict *qdict) -{ - int i; - CaptureState *s; - - for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { - monitor_printf(mon, "[%d]: ", i); - s->ops.info (s->opaque); - } -} - -static void hmp_stopcapture(Monitor *mon, const QDict *qdict) -{ - int i; - int n = qdict_get_int(qdict, "n"); - CaptureState *s; - - for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { - if (i == n) { - s->ops.destroy (s->opaque); - QLIST_REMOVE (s, entries); - g_free (s); - return; - } - } -} - -static void hmp_wavcapture(Monitor *mon, const QDict *qdict) -{ - const char *path = qdict_get_str(qdict, "path"); - int freq = qdict_get_try_int(qdict, "freq", 44100); - int bits = qdict_get_try_int(qdict, "bits", 16); - int nchannels = qdict_get_try_int(qdict, "nchannels", 2); - const char *audiodev = qdict_get_str(qdict, "audiodev"); - CaptureState *s; - AudioState *as = audio_state_by_name(audiodev); - - if (!as) { - monitor_printf(mon, "Audiodev '%s' not found\n", audiodev); - return; - } - - s = g_malloc0 (sizeof (*s)); - - if (wav_start_capture(as, s, path, freq, bits, nchannels)) { - monitor_printf(mon, "Failed to add wave capture\n"); - g_free (s); - return; - } - QLIST_INSERT_HEAD (&capture_head, s, entries); -} - void qmp_getfd(const char *fdname, Error **errp) { Monitor *cur_mon = monitor_cur(); From b7d75c0b4816b2d766671f1e5a64de1251526686 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:17 +0100 Subject: [PATCH 440/814] char: Move HMP commands from monitor/ to chardev/ This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Character device backends". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-4-armbru@redhat.com> --- chardev/char-hmp-cmds.c | 220 ++++++++++++++++++++++++++++++++++++++++ chardev/meson.build | 6 +- monitor/hmp-cmds.c | 123 ---------------------- monitor/misc.c | 78 -------------- 4 files changed, 225 insertions(+), 202 deletions(-) create mode 100644 chardev/char-hmp-cmds.c diff --git a/chardev/char-hmp-cmds.c b/chardev/char-hmp-cmds.c new file mode 100644 index 0000000000..287c2b1bcd --- /dev/null +++ b/chardev/char-hmp-cmds.c @@ -0,0 +1,220 @@ +/* + * HMP commands related to character devices + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "chardev/char.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-char.h" +#include "qapi/qmp/qdict.h" +#include "qemu/config-file.h" +#include "qemu/option.h" + +void hmp_info_chardev(Monitor *mon, const QDict *qdict) +{ + ChardevInfoList *char_info, *info; + + char_info = qmp_query_chardev(NULL); + for (info = char_info; info; info = info->next) { + monitor_printf(mon, "%s: filename=%s\n", info->value->label, + info->value->filename); + } + + qapi_free_ChardevInfoList(char_info); +} + +void hmp_ringbuf_write(Monitor *mon, const QDict *qdict) +{ + const char *chardev = qdict_get_str(qdict, "device"); + const char *data = qdict_get_str(qdict, "data"); + Error *err = NULL; + + qmp_ringbuf_write(chardev, data, false, 0, &err); + + hmp_handle_error(mon, err); +} + +void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) +{ + uint32_t size = qdict_get_int(qdict, "size"); + const char *chardev = qdict_get_str(qdict, "device"); + char *data; + Error *err = NULL; + int i; + + data = qmp_ringbuf_read(chardev, size, false, 0, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + for (i = 0; data[i]; i++) { + unsigned char ch = data[i]; + + if (ch == '\\') { + monitor_printf(mon, "\\\\"); + } else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) { + monitor_printf(mon, "\\u%04X", ch); + } else { + monitor_printf(mon, "%c", ch); + } + + } + monitor_printf(mon, "\n"); + g_free(data); +} + +void hmp_chardev_add(Monitor *mon, const QDict *qdict) +{ + const char *args = qdict_get_str(qdict, "args"); + Error *err = NULL; + QemuOpts *opts; + + opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, true); + if (opts == NULL) { + error_setg(&err, "Parsing chardev args failed"); + } else { + qemu_chr_new_from_opts(opts, NULL, &err); + qemu_opts_del(opts); + } + hmp_handle_error(mon, err); +} + +void hmp_chardev_change(Monitor *mon, const QDict *qdict) +{ + const char *args = qdict_get_str(qdict, "args"); + const char *id; + Error *err = NULL; + ChardevBackend *backend = NULL; + ChardevReturn *ret = NULL; + QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, + true); + if (!opts) { + error_setg(&err, "Parsing chardev args failed"); + goto end; + } + + id = qdict_get_str(qdict, "id"); + if (qemu_opts_id(opts)) { + error_setg(&err, "Unexpected 'id' parameter"); + goto end; + } + + backend = qemu_chr_parse_opts(opts, &err); + if (!backend) { + goto end; + } + + ret = qmp_chardev_change(id, backend, &err); + +end: + qapi_free_ChardevReturn(ret); + qapi_free_ChardevBackend(backend); + qemu_opts_del(opts); + hmp_handle_error(mon, err); +} + +void hmp_chardev_remove(Monitor *mon, const QDict *qdict) +{ + Error *local_err = NULL; + + qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err); + hmp_handle_error(mon, local_err); +} + +void hmp_chardev_send_break(Monitor *mon, const QDict *qdict) +{ + Error *local_err = NULL; + + qmp_chardev_send_break(qdict_get_str(qdict, "id"), &local_err); + hmp_handle_error(mon, local_err); +} + +void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + ChardevBackendInfoList *list, *start; + + if (nb_args != 2) { + return; + } + len = strlen(str); + readline_set_completion_index(rs, len); + + start = list = qmp_query_chardev_backends(NULL); + while (list) { + const char *chr_name = list->value->name; + + if (!strncmp(chr_name, str, len)) { + readline_add_completion(rs, chr_name); + } + list = list->next; + } + qapi_free_ChardevBackendInfoList(start); +} + +void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + ChardevInfoList *list, *start; + + if (nb_args != 2) { + return; + } + len = strlen(str); + readline_set_completion_index(rs, len); + + start = list = qmp_query_chardev(NULL); + while (list) { + ChardevInfo *chr = list->value; + + if (!strncmp(chr->label, str, len)) { + readline_add_completion(rs, chr->label); + } + list = list->next; + } + qapi_free_ChardevInfoList(start); +} + +static void ringbuf_completion(ReadLineState *rs, const char *str) +{ + size_t len; + ChardevInfoList *list, *start; + + len = strlen(str); + readline_set_completion_index(rs, len); + + start = list = qmp_query_chardev(NULL); + while (list) { + ChardevInfo *chr_info = list->value; + + if (!strncmp(chr_info->label, str, len)) { + Chardev *chr = qemu_chr_find(chr_info->label); + if (chr && CHARDEV_IS_RINGBUF(chr)) { + readline_add_completion(rs, chr_info->label); + } + } + list = list->next; + } + qapi_free_ChardevInfoList(start); +} + +void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str) +{ + if (nb_args != 2) { + return; + } + ringbuf_completion(rs, str); +} diff --git a/chardev/meson.build b/chardev/meson.build index 789b50056a..7a3ba777ab 100644 --- a/chardev/meson.build +++ b/chardev/meson.build @@ -28,7 +28,11 @@ chardev_ss.add(when: 'CONFIG_WIN32', if_true: files( chardev_ss = chardev_ss.apply(config_host, strict: false) -softmmu_ss.add(files('msmouse.c', 'wctablet.c', 'testdev.c')) +softmmu_ss.add(files( + 'char-hmp-cmds.c', + 'msmouse.c', + 'wctablet.c', + 'testdev.c')) chardev_modules = {} diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index de1a96d48c..c8ed59c281 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -17,10 +17,7 @@ #include "monitor/hmp.h" #include "net/net.h" #include "net/eth.h" -#include "chardev/char.h" #include "sysemu/runstate.h" -#include "qemu/config-file.h" -#include "qemu/option.h" #include "qemu/sockets.h" #include "qemu/help_option.h" #include "monitor/monitor.h" @@ -28,7 +25,6 @@ #include "qapi/clone-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-block.h" -#include "qapi/qapi-commands-char.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-migration.h" @@ -155,19 +151,6 @@ void hmp_info_uuid(Monitor *mon, const QDict *qdict) qapi_free_UuidInfo(info); } -void hmp_info_chardev(Monitor *mon, const QDict *qdict) -{ - ChardevInfoList *char_info, *info; - - char_info = qmp_query_chardev(NULL); - for (info = char_info; info; info = info->next) { - monitor_printf(mon, "%s: filename=%s\n", info->value->label, - info->value->filename); - } - - qapi_free_ChardevInfoList(char_info); -} - void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; @@ -673,46 +656,6 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_ringbuf_write(Monitor *mon, const QDict *qdict) -{ - const char *chardev = qdict_get_str(qdict, "device"); - const char *data = qdict_get_str(qdict, "data"); - Error *err = NULL; - - qmp_ringbuf_write(chardev, data, false, 0, &err); - - hmp_handle_error(mon, err); -} - -void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) -{ - uint32_t size = qdict_get_int(qdict, "size"); - const char *chardev = qdict_get_str(qdict, "device"); - char *data; - Error *err = NULL; - int i; - - data = qmp_ringbuf_read(chardev, size, false, 0, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - for (i = 0; data[i]; i++) { - unsigned char ch = data[i]; - - if (ch == '\\') { - monitor_printf(mon, "\\\\"); - } else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) { - monitor_printf(mon, "\\u%04X", ch); - } else { - monitor_printf(mon, "%c", ch); - } - - } - monitor_printf(mon, "\n"); - g_free(data); -} - void hmp_cont(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -1241,72 +1184,6 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_chardev_add(Monitor *mon, const QDict *qdict) -{ - const char *args = qdict_get_str(qdict, "args"); - Error *err = NULL; - QemuOpts *opts; - - opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, true); - if (opts == NULL) { - error_setg(&err, "Parsing chardev args failed"); - } else { - qemu_chr_new_from_opts(opts, NULL, &err); - qemu_opts_del(opts); - } - hmp_handle_error(mon, err); -} - -void hmp_chardev_change(Monitor *mon, const QDict *qdict) -{ - const char *args = qdict_get_str(qdict, "args"); - const char *id; - Error *err = NULL; - ChardevBackend *backend = NULL; - ChardevReturn *ret = NULL; - QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, - true); - if (!opts) { - error_setg(&err, "Parsing chardev args failed"); - goto end; - } - - id = qdict_get_str(qdict, "id"); - if (qemu_opts_id(opts)) { - error_setg(&err, "Unexpected 'id' parameter"); - goto end; - } - - backend = qemu_chr_parse_opts(opts, &err); - if (!backend) { - goto end; - } - - ret = qmp_chardev_change(id, backend, &err); - -end: - qapi_free_ChardevReturn(ret); - qapi_free_ChardevBackend(backend); - qemu_opts_del(opts); - hmp_handle_error(mon, err); -} - -void hmp_chardev_remove(Monitor *mon, const QDict *qdict) -{ - Error *local_err = NULL; - - qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err); - hmp_handle_error(mon, local_err); -} - -void hmp_chardev_send_break(Monitor *mon, const QDict *qdict) -{ - Error *local_err = NULL; - - qmp_chardev_send_break(qdict_get_str(qdict, "id"), &local_err); - hmp_handle_error(mon, local_err); -} - void hmp_object_del(Monitor *mon, const QDict *qdict) { const char *id = qdict_get_str(qdict, "id"); diff --git a/monitor/misc.c b/monitor/misc.c index 80d5527774..c18a713d9c 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -49,7 +49,6 @@ #include "exec/ioport.h" #include "block/qapi.h" #include "block/block-hmp-cmds.h" -#include "qapi/qapi-commands-char.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" @@ -1362,29 +1361,6 @@ static void add_completion_option(ReadLineState *rs, const char *str, } } -void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - ChardevBackendInfoList *list, *start; - - if (nb_args != 2) { - return; - } - len = strlen(str); - readline_set_completion_index(rs, len); - - start = list = qmp_query_chardev_backends(NULL); - while (list) { - const char *chr_name = list->value->name; - - if (!strncmp(chr_name, str, len)) { - readline_add_completion(rs, chr_name); - } - list = list->next; - } - qapi_free_ChardevBackendInfoList(start); -} - void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; @@ -1498,60 +1474,6 @@ static void peripheral_device_del_completion(ReadLineState *rs, g_slist_free(list); } -void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - ChardevInfoList *list, *start; - - if (nb_args != 2) { - return; - } - len = strlen(str); - readline_set_completion_index(rs, len); - - start = list = qmp_query_chardev(NULL); - while (list) { - ChardevInfo *chr = list->value; - - if (!strncmp(chr->label, str, len)) { - readline_add_completion(rs, chr->label); - } - list = list->next; - } - qapi_free_ChardevInfoList(start); -} - -static void ringbuf_completion(ReadLineState *rs, const char *str) -{ - size_t len; - ChardevInfoList *list, *start; - - len = strlen(str); - readline_set_completion_index(rs, len); - - start = list = qmp_query_chardev(NULL); - while (list) { - ChardevInfo *chr_info = list->value; - - if (!strncmp(chr_info->label, str, len)) { - Chardev *chr = qemu_chr_find(chr_info->label); - if (chr && CHARDEV_IS_RINGBUF(chr)) { - readline_add_completion(rs, chr_info->label); - } - } - list = list->next; - } - qapi_free_ChardevInfoList(start); -} - -void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str) -{ - if (nb_args != 2) { - return; - } - ringbuf_completion(rs, str); -} - void device_del_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; From c3054a6e6a8c191b20f981a022270af1ead0ab29 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:18 +0100 Subject: [PATCH 441/814] char: Factor out qmp_add_client() parts and move to chardev/ Code moves from MAINTAINERS section "QMP" to "Character device backends". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-5-armbru@redhat.com> --- chardev/char.c | 20 ++++++++++++++++++++ include/monitor/qmp-helpers.h | 3 +++ monitor/qmp-cmds.c | 13 ++----------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/chardev/char.c b/chardev/char.c index 87ab6efbcc..11eab7764c 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "monitor/monitor.h" +#include "monitor/qmp-helpers.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" @@ -1166,6 +1167,25 @@ void qmp_chardev_send_break(const char *id, Error **errp) qemu_chr_be_event(chr, CHR_EVENT_BREAK); } +bool qmp_add_client_char(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, const char *protocol, + Error **errp) +{ + Chardev *s = qemu_chr_find(protocol); + + if (!s) { + error_setg(errp, "protocol '%s' is invalid", protocol); + close(fd); + return false; + } + if (qemu_chr_add_client(s, fd) < 0) { + error_setg(errp, "failed to add client"); + close(fd); + return false; + } + return true; +} + /* * Add a timeout callback for the chardev (in milliseconds), return * the GSource object created. Please use this to add timeout hook for diff --git a/include/monitor/qmp-helpers.h b/include/monitor/qmp-helpers.h index 4718c63c73..318c3357a2 100644 --- a/include/monitor/qmp-helpers.h +++ b/include/monitor/qmp-helpers.h @@ -22,5 +22,8 @@ bool qmp_add_client_vnc(int fd, bool has_skipauth, bool skipauth, bool qmp_add_client_dbus_display(int fd, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp); #endif +bool qmp_add_client_char(int fd, bool has_skipauth, bool skipauth, + bool has_tls, bool tls, const char *protocol, + Error **errp); #endif diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 743849c0b5..e5ab77f6c6 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -17,7 +17,6 @@ #include "monitor/monitor.h" #include "monitor/qmp-helpers.h" #include "sysemu/sysemu.h" -#include "chardev/char.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "sysemu/runstate-action.h" @@ -174,7 +173,6 @@ void qmp_add_client(const char *protocol, const char *fdname, { "@dbus-display", qmp_add_client_dbus_display }, #endif }; - Chardev *s; int fd, i; fd = monitor_get_fd(monitor_cur(), fdname, errp); @@ -192,16 +190,9 @@ void qmp_add_client(const char *protocol, const char *fdname, } } - s = qemu_chr_find(protocol); - if (!s) { - error_setg(errp, "protocol '%s' is invalid", protocol); + if (!qmp_add_client_char(fd, has_skipauth, skipauth, has_tls, tls, + protocol, errp)) { close(fd); - return; - } - if (qemu_chr_add_client(s, fd) < 0) { - error_setg(errp, "failed to add client"); - close(fd); - return; } } From 444ee02c5ff3b1ce794e9dc2fe2005a13ae8e4a7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:19 +0100 Subject: [PATCH 442/814] hmp: Drop redundant argument check from add_completion_option() No need to check for null arguments, no caller passes them. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-6-armbru@redhat.com> --- monitor/misc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index c18a713d9c..d58a81c452 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1353,9 +1353,6 @@ int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) static void add_completion_option(ReadLineState *rs, const char *str, const char *option) { - if (!str || !option) { - return; - } if (!strncmp(option, str, strlen(str))) { readline_add_completion(rs, option); } From 52f50b1e9f8fd410d4293a211d549ec61b902728 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:20 +0100 Subject: [PATCH 443/814] readline: Extract readline_add_completion_of() from monitor monitor/misc.h has static add_completion_option(). It's useful elsewhere in the monitor. Since it's not monitor-specific, move it to util/readline.c renamed to readline_add_completion_of(), and put it to use. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-7-armbru@redhat.com> --- include/qemu/readline.h | 2 + monitor/hmp.c | 12 +++--- monitor/misc.c | 85 +++++++++++++---------------------------- util/readline.c | 8 ++++ 4 files changed, 41 insertions(+), 66 deletions(-) diff --git a/include/qemu/readline.h b/include/qemu/readline.h index 622aa4564f..b05e4782da 100644 --- a/include/qemu/readline.h +++ b/include/qemu/readline.h @@ -44,6 +44,8 @@ typedef struct ReadLineState { } ReadLineState; void readline_add_completion(ReadLineState *rs, const char *str); +void readline_add_completion_of(ReadLineState *rs, + const char *pfx, const char *str); void readline_set_completion_index(ReadLineState *rs, int completion_index); const char *readline_get_history(ReadLineState *rs, unsigned int index); diff --git a/monitor/hmp.c b/monitor/hmp.c index e5d914b1f5..1b04f01244 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1189,8 +1189,8 @@ static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) } memcpy(cmd, pstart, len); cmd[len] = '\0'; - if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) { - readline_add_completion(mon->rs, cmd); + if (name[0] == '\0') { + readline_add_completion_of(mon->rs, name, cmd); } if (*p == '\0') { break; @@ -1270,7 +1270,7 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, { const char *cmdname; int i; - const char *ptype, *old_ptype, *str, *name; + const char *ptype, *old_ptype, *str; const HMPCommand *cmd; BlockBackend *blk = NULL; @@ -1335,10 +1335,8 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, /* block device name completion */ readline_set_completion_index(mon->rs, strlen(str)); while ((blk = blk_next(blk)) != NULL) { - name = blk_name(blk); - if (str[0] == '\0' || - !strncmp(name, str, strlen(str))) { - readline_add_completion(mon->rs, name); + if (str[0] == '\0') { + readline_add_completion_of(mon->rs, str, blk_name(blk)); } } break; diff --git a/monitor/misc.c b/monitor/misc.c index d58a81c452..9da52939b2 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1350,14 +1350,6 @@ int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) return ret; } -static void add_completion_option(ReadLineState *rs, const char *str, - const char *option) -{ - if (!strncmp(option, str, strlen(str))) { - readline_add_completion(rs, option); - } -} - void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; @@ -1369,7 +1361,7 @@ void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) len = strlen(str); readline_set_completion_index(rs, len); for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) { - add_completion_option(rs, str, NetClientDriver_str(i)); + readline_add_completion_of(rs, str, NetClientDriver_str(i)); } } @@ -1386,14 +1378,12 @@ void device_add_completion(ReadLineState *rs, int nb_args, const char *str) readline_set_completion_index(rs, len); list = elt = object_class_get_list(TYPE_DEVICE, false); while (elt) { - const char *name; DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, TYPE_DEVICE); - name = object_class_get_name(OBJECT_CLASS(dc)); - if (dc->user_creatable - && !strncmp(name, str, len)) { - readline_add_completion(rs, name); + if (dc->user_creatable) { + readline_add_completion_of(rs, str, + object_class_get_name(OBJECT_CLASS(dc))); } elt = elt->next; } @@ -1416,8 +1406,8 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str) const char *name; name = object_class_get_name(OBJECT_CLASS(elt->data)); - if (!strncmp(name, str, len) && strcmp(name, TYPE_USER_CREATABLE)) { - readline_add_completion(rs, name); + if (strcmp(name, TYPE_USER_CREATABLE)) { + readline_add_completion_of(rs, str, name); } elt = elt->next; } @@ -1450,7 +1440,7 @@ static GSList *qdev_build_hotpluggable_device_list(Object *peripheral) } static void peripheral_device_del_completion(ReadLineState *rs, - const char *str, size_t len) + const char *str) { Object *peripheral = container_get(qdev_get_machine(), "/peripheral"); GSList *list, *item; @@ -1463,8 +1453,8 @@ static void peripheral_device_del_completion(ReadLineState *rs, for (item = list; item; item = g_slist_next(item)) { DeviceState *dev = item->data; - if (dev->id && !strncmp(str, dev->id, len)) { - readline_add_completion(rs, dev->id); + if (dev->id) { + readline_add_completion_of(rs, str, dev->id); } } @@ -1473,15 +1463,12 @@ static void peripheral_device_del_completion(ReadLineState *rs, void device_del_completion(ReadLineState *rs, int nb_args, const char *str) { - size_t len; - if (nb_args != 2) { return; } - len = strlen(str); - readline_set_completion_index(rs, len); - peripheral_device_del_completion(rs, str, len); + readline_set_completion_index(rs, strlen(str)); + peripheral_device_del_completion(rs, str); } void object_del_completion(ReadLineState *rs, int nb_args, const char *str) @@ -1499,9 +1486,8 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str) while (list) { ObjectPropertyInfo *info = list->value; - if (!strncmp(info->type, "child<", 5) - && !strncmp(info->name, str, len)) { - readline_add_completion(rs, info->name); + if (!strncmp(info->type, "child<", 5)) { + readline_add_completion_of(rs, str, info->name); } list = list->next; } @@ -1521,14 +1507,11 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str) NET_CLIENT_DRIVER_NONE, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { - const char *name = ncs[i]->name; - if (!strncmp(str, name, len)) { - readline_add_completion(rs, name); - } + readline_add_completion_of(rs, str, ncs[i]->name); } } else if (nb_args == 3) { - add_completion_option(rs, str, "on"); - add_completion_option(rs, str, "off"); + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); } } @@ -1546,12 +1529,8 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { - const char *name = ncs[i]->name; - if (strncmp(str, name, len)) { - continue; - } if (ncs[i]->is_netdev) { - readline_add_completion(rs, name); + readline_add_completion_of(rs, str, ncs[i]->name); } } } @@ -1590,8 +1569,8 @@ void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) } g_free(pattern); } else if (nb_args == 3) { - add_completion_option(rs, str, "on"); - add_completion_option(rs, str, "off"); + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); } } @@ -1604,7 +1583,7 @@ void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) } readline_set_completion_index(rs, strlen(str)); for (i = 0; i < WATCHDOG_ACTION__MAX; i++) { - add_completion_option(rs, str, WatchdogAction_str(i)); + readline_add_completion_of(rs, str, WatchdogAction_str(i)); } } @@ -1618,14 +1597,11 @@ void migrate_set_capability_completion(ReadLineState *rs, int nb_args, if (nb_args == 2) { int i; for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { - const char *name = MigrationCapability_str(i); - if (!strncmp(str, name, len)) { - readline_add_completion(rs, name); - } + readline_add_completion_of(rs, str, MigrationCapability_str(i)); } } else if (nb_args == 3) { - add_completion_option(rs, str, "on"); - add_completion_option(rs, str, "off"); + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); } } @@ -1639,10 +1615,7 @@ void migrate_set_parameter_completion(ReadLineState *rs, int nb_args, if (nb_args == 2) { int i; for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { - const char *name = MigrationParameter_str(i); - if (!strncmp(str, name, len)) { - readline_add_completion(rs, name); - } + readline_add_completion_of(rs, str, MigrationParameter_str(i)); } } } @@ -1672,14 +1645,8 @@ static void vm_completion(ReadLineState *rs, const char *str) snapshot = snapshots; while (snapshot) { - char *completion = snapshot->value->name; - if (!strncmp(str, completion, len)) { - readline_add_completion(rs, completion); - } - completion = snapshot->value->id; - if (!strncmp(str, completion, len)) { - readline_add_completion(rs, completion); - } + readline_add_completion_of(rs, str, snapshot->value->name); + readline_add_completion_of(rs, str, snapshot->value->id); snapshot = snapshot->next; } qapi_free_SnapshotInfoList(snapshots); diff --git a/util/readline.c b/util/readline.c index f1ac6e4769..494a3d924e 100644 --- a/util/readline.c +++ b/util/readline.c @@ -286,6 +286,14 @@ void readline_add_completion(ReadLineState *rs, const char *str) } } +void readline_add_completion_of(ReadLineState *rs, + const char *pfx, const char *str) +{ + if (!strncmp(str, pfx, strlen(pfx))) { + readline_add_completion(rs, str); + } +} + void readline_set_completion_index(ReadLineState *rs, int index) { rs->completion_index = index; From 5ec92f2d92709964bd9247346097536c02394b3a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:21 +0100 Subject: [PATCH 444/814] hmp: Rename help_cmd() to hmp_help_cmd(), move declaration to hmp.h The next commit will move a caller of help_cmd() to a new file. Including monitor/monitor-internal.h there just for help_cmd() feels silly. Better to provide it in monitor/hmp.h suitably renamed. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-8-armbru@redhat.com> --- include/monitor/hmp.h | 1 + monitor/hmp.c | 2 +- monitor/misc.c | 8 ++++---- monitor/monitor-internal.h | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index c25bec1863..5a75f4659c 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -18,6 +18,7 @@ #include "qapi/qapi-types-common.h" bool hmp_handle_error(Monitor *mon, Error *err); +void hmp_help_cmd(Monitor *mon, const char *name); void hmp_info_name(Monitor *mon, const QDict *qdict); void hmp_info_version(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp.c b/monitor/hmp.c index 1b04f01244..2aa85d3982 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -272,7 +272,7 @@ static void help_cmd_dump(Monitor *mon, const HMPCommand *cmds, } } -void help_cmd(Monitor *mon, const char *name) +void hmp_help_cmd(Monitor *mon, const char *name) { char *args[MAX_ARGS]; int nb_args = 0; diff --git a/monitor/misc.c b/monitor/misc.c index 9da52939b2..240d137327 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -153,7 +153,7 @@ int hmp_compare_cmd(const char *name, const char *list) static void do_help_cmd(Monitor *mon, const QDict *qdict) { - help_cmd(mon, qdict_get_try_str(qdict, "name")); + hmp_help_cmd(mon, qdict_get_try_str(qdict, "name")); } static void hmp_trace_event(Monitor *mon, const QDict *qdict) @@ -195,14 +195,14 @@ static void hmp_trace_file(Monitor *mon, const QDict *qdict) } } else { monitor_printf(mon, "unexpected argument \"%s\"\n", op); - help_cmd(mon, "trace-file"); + hmp_help_cmd(mon, "trace-file"); } } #endif static void hmp_info_help(Monitor *mon, const QDict *qdict) { - help_cmd(mon, "info"); + hmp_help_cmd(mon, "info"); } static void monitor_init_qmp_commands(void) @@ -424,7 +424,7 @@ static void hmp_log(Monitor *mon, const QDict *qdict) } else { mask = qemu_str_to_log_mask(items); if (!mask) { - help_cmd(mon, "log"); + hmp_help_cmd(mon, "log"); return; } } diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index a2cdbbf646..53e3808054 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -186,7 +186,6 @@ void monitor_data_destroy_qmp(MonitorQMP *mon); void coroutine_fn monitor_qmp_dispatcher_co(void *data); int get_monitor_def(Monitor *mon, int64_t *pval, const char *name); -void help_cmd(Monitor *mon, const char *name); void handle_hmp_command(MonitorHMP *mon, const char *cmdline); int hmp_compare_cmd(const char *name, const char *list); From 29b62a1063c662e9564d23c716103adde2c94ca8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:22 +0100 Subject: [PATCH 445/814] trace: Move HMP commands from monitor/ to trace/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Tracing". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-9-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi --- include/monitor/hmp.h | 3 + monitor/misc.c | 119 --------------------------------- trace/meson.build | 1 + trace/trace-hmp-cmds.c | 148 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 119 deletions(-) create mode 100644 trace/trace-hmp-cmds.c diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 5a75f4659c..58ed1bec62 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -155,5 +155,8 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); void hmp_info_capture(Monitor *mon, const QDict *qdict); void hmp_stopcapture(Monitor *mon, const QDict *qdict); void hmp_wavcapture(Monitor *mon, const QDict *qdict); +void hmp_trace_event(Monitor *mon, const QDict *qdict); +void hmp_trace_file(Monitor *mon, const QDict *qdict); +void hmp_info_trace_events(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor/misc.c b/monitor/misc.c index 240d137327..2a6bc13e7f 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -39,12 +39,8 @@ #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qom/object_interfaces.h" -#include "trace/control.h" #include "monitor/hmp-target.h" #include "monitor/hmp.h" -#ifdef CONFIG_TRACE_SIMPLE -#include "trace/simple.h" -#endif #include "exec/address-spaces.h" #include "exec/ioport.h" #include "block/qapi.h" @@ -54,7 +50,6 @@ #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-qom.h" #include "qapi/qapi-commands-run-state.h" -#include "qapi/qapi-commands-trace.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-init-commands.h" #include "qapi/error.h" @@ -156,50 +151,6 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict) hmp_help_cmd(mon, qdict_get_try_str(qdict, "name")); } -static void hmp_trace_event(Monitor *mon, const QDict *qdict) -{ - const char *tp_name = qdict_get_str(qdict, "name"); - bool new_state = qdict_get_bool(qdict, "option"); - bool has_vcpu = qdict_haskey(qdict, "vcpu"); - int vcpu = qdict_get_try_int(qdict, "vcpu", 0); - Error *local_err = NULL; - - if (vcpu < 0) { - monitor_printf(mon, "argument vcpu must be positive"); - return; - } - - qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err); - if (local_err) { - error_report_err(local_err); - } -} - -#ifdef CONFIG_TRACE_SIMPLE -static void hmp_trace_file(Monitor *mon, const QDict *qdict) -{ - const char *op = qdict_get_try_str(qdict, "op"); - const char *arg = qdict_get_try_str(qdict, "arg"); - - if (!op) { - st_print_trace_file_status(); - } else if (!strcmp(op, "on")) { - st_set_trace_file_enabled(true); - } else if (!strcmp(op, "off")) { - st_set_trace_file_enabled(false); - } else if (!strcmp(op, "flush")) { - st_flush_trace_buffer(); - } else if (!strcmp(op, "set")) { - if (arg) { - st_set_trace_file(arg); - } - } else { - monitor_printf(mon, "unexpected argument \"%s\"\n", op); - hmp_help_cmd(mon, "trace-file"); - } -} -#endif - static void hmp_info_help(Monitor *mon, const QDict *qdict) { hmp_help_cmd(mon, "info"); @@ -344,37 +295,6 @@ static void hmp_info_history(Monitor *mon, const QDict *qdict) } } -static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) -{ - const char *name = qdict_get_try_str(qdict, "name"); - bool has_vcpu = qdict_haskey(qdict, "vcpu"); - int vcpu = qdict_get_try_int(qdict, "vcpu", 0); - TraceEventInfoList *events; - TraceEventInfoList *elem; - Error *local_err = NULL; - - if (name == NULL) { - name = "*"; - } - if (vcpu < 0) { - monitor_printf(mon, "argument vcpu must be positive"); - return; - } - - events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err); - if (local_err) { - error_report_err(local_err); - return; - } - - for (elem = events; elem != NULL; elem = elem->next) { - monitor_printf(mon, "%s : state %u\n", - elem->value->name, - elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0); - } - qapi_free_TraceEventInfoList(events); -} - void qmp_client_migrate_info(const char *protocol, const char *hostname, bool has_port, int64_t port, bool has_tls_port, int64_t tls_port, @@ -1535,45 +1455,6 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) } } -void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - - len = strlen(str); - readline_set_completion_index(rs, len); - if (nb_args == 2) { - TraceEventIter iter; - TraceEvent *ev; - char *pattern = g_strdup_printf("%s*", str); - trace_event_iter_init_pattern(&iter, pattern); - while ((ev = trace_event_iter_next(&iter)) != NULL) { - readline_add_completion(rs, trace_event_get_name(ev)); - } - g_free(pattern); - } -} - -void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - - len = strlen(str); - readline_set_completion_index(rs, len); - if (nb_args == 2) { - TraceEventIter iter; - TraceEvent *ev; - char *pattern = g_strdup_printf("%s*", str); - trace_event_iter_init_pattern(&iter, pattern); - while ((ev = trace_event_iter_next(&iter)) != NULL) { - readline_add_completion(rs, trace_event_get_name(ev)); - } - g_free(pattern); - } else if (nb_args == 3) { - readline_add_completion_of(rs, str, "on"); - readline_add_completion_of(rs, str, "off"); - } -} - void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) { int i; diff --git a/trace/meson.build b/trace/meson.build index 26b54714d5..d565948b09 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -1,3 +1,4 @@ +softmmu_ss.add(files('trace-hmp-cmds.c')) specific_ss.add(files('control-target.c')) diff --git a/trace/trace-hmp-cmds.c b/trace/trace-hmp-cmds.c new file mode 100644 index 0000000000..792876c34a --- /dev/null +++ b/trace/trace-hmp-cmds.c @@ -0,0 +1,148 @@ +/* + * HMP commands related to tracing + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-trace.h" +#include "qapi/qmp/qdict.h" +#include "trace/control.h" +#ifdef CONFIG_TRACE_SIMPLE +#include "trace/simple.h" +#endif + +void hmp_trace_event(Monitor *mon, const QDict *qdict) +{ + const char *tp_name = qdict_get_str(qdict, "name"); + bool new_state = qdict_get_bool(qdict, "option"); + bool has_vcpu = qdict_haskey(qdict, "vcpu"); + int vcpu = qdict_get_try_int(qdict, "vcpu", 0); + Error *local_err = NULL; + + if (vcpu < 0) { + monitor_printf(mon, "argument vcpu must be positive"); + return; + } + + qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err); + if (local_err) { + error_report_err(local_err); + } +} + +#ifdef CONFIG_TRACE_SIMPLE +void hmp_trace_file(Monitor *mon, const QDict *qdict) +{ + const char *op = qdict_get_try_str(qdict, "op"); + const char *arg = qdict_get_try_str(qdict, "arg"); + + if (!op) { + st_print_trace_file_status(); + } else if (!strcmp(op, "on")) { + st_set_trace_file_enabled(true); + } else if (!strcmp(op, "off")) { + st_set_trace_file_enabled(false); + } else if (!strcmp(op, "flush")) { + st_flush_trace_buffer(); + } else if (!strcmp(op, "set")) { + if (arg) { + st_set_trace_file(arg); + } + } else { + monitor_printf(mon, "unexpected argument \"%s\"\n", op); + hmp_help_cmd(mon, "trace-file"); + } +} +#endif + +void hmp_info_trace_events(Monitor *mon, const QDict *qdict) +{ + const char *name = qdict_get_try_str(qdict, "name"); + bool has_vcpu = qdict_haskey(qdict, "vcpu"); + int vcpu = qdict_get_try_int(qdict, "vcpu", 0); + TraceEventInfoList *events; + TraceEventInfoList *elem; + Error *local_err = NULL; + + if (name == NULL) { + name = "*"; + } + if (vcpu < 0) { + monitor_printf(mon, "argument vcpu must be positive"); + return; + } + + events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err); + if (local_err) { + error_report_err(local_err); + return; + } + + for (elem = events; elem != NULL; elem = elem->next) { + monitor_printf(mon, "%s : state %u\n", + elem->value->name, + elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0); + } + qapi_free_TraceEventInfoList(events); +} + +void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + TraceEventIter iter; + TraceEvent *ev; + char *pattern = g_strdup_printf("%s*", str); + trace_event_iter_init_pattern(&iter, pattern); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + readline_add_completion(rs, trace_event_get_name(ev)); + } + g_free(pattern); + } +} + +void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + TraceEventIter iter; + TraceEvent *ev; + char *pattern = g_strdup_printf("%s*", str); + trace_event_iter_init_pattern(&iter, pattern); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + readline_add_completion(rs, trace_event_get_name(ev)); + } + g_free(pattern); + } else if (nb_args == 3) { + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); + } +} From d9c631ea9f428afb32d0fa1399e4fcb9faeaa3b8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:23 +0100 Subject: [PATCH 446/814] machine: Move QMP commands from monitor/ to hw/core/ This moves these commands from MAINTAINERS section "QMP" to "Machine core". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-10-armbru@redhat.com> --- hw/core/machine-qmp-cmds.c | 144 +++++++++++++++++++++++++++++++++++++ monitor/qmp-cmds.c | 140 ------------------------------------ 2 files changed, 144 insertions(+), 140 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 80d5e59651..44b5da8880 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -9,6 +9,9 @@ #include "qemu/osdep.h" #include "hw/boards.h" +#include "hw/intc/intc.h" +#include "hw/mem/memory-device.h" +#include "hw/rdma/rdma.h" #include "qapi/error.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-machine.h" @@ -17,11 +20,13 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/type-helpers.h" #include "qemu/main-loop.h" +#include "qemu/uuid.h" #include "qom/qom-qobject.h" #include "sysemu/hostmem.h" #include "sysemu/hw_accel.h" #include "sysemu/numa.h" #include "sysemu/runstate.h" +#include "sysemu/sysemu.h" static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu) { @@ -239,3 +244,142 @@ HumanReadableText *qmp_x_query_numa(Error **errp) done: return human_readable_text_from_str(buf); } + +KvmInfo *qmp_query_kvm(Error **errp) +{ + KvmInfo *info = g_malloc0(sizeof(*info)); + + info->enabled = kvm_enabled(); + info->present = accel_find("kvm"); + + return info; +} + +UuidInfo *qmp_query_uuid(Error **errp) +{ + UuidInfo *info = g_malloc0(sizeof(*info)); + + info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); + return info; +} + +void qmp_system_reset(Error **errp) +{ + qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); +} + +void qmp_system_powerdown(Error **errp) +{ + qemu_system_powerdown_request(); +} + +void qmp_system_wakeup(Error **errp) +{ + if (!qemu_wakeup_suspend_enabled()) { + error_setg(errp, + "wake-up from suspend is not supported by this guest"); + return; + } + + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); +} + +MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) +{ + return qmp_memory_device_list(); +} + +MemoryInfo *qmp_query_memory_size_summary(Error **errp) +{ + MemoryInfo *mem_info = g_new0(MemoryInfo, 1); + MachineState *ms = MACHINE(qdev_get_machine()); + + mem_info->base_memory = ms->ram_size; + + mem_info->plugged_memory = get_plugged_memory_size(); + mem_info->has_plugged_memory = + mem_info->plugged_memory != (uint64_t)-1; + + return mem_info; +} + +static int qmp_x_query_rdma_foreach(Object *obj, void *opaque) +{ + RdmaProvider *rdma; + RdmaProviderClass *k; + GString *buf = opaque; + + if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) { + rdma = RDMA_PROVIDER(obj); + k = RDMA_PROVIDER_GET_CLASS(obj); + if (k->format_statistics) { + k->format_statistics(rdma, buf); + } else { + g_string_append_printf(buf, + "RDMA statistics not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +HumanReadableText *qmp_x_query_rdma(Error **errp) +{ + g_autoptr(GString) buf = g_string_new(""); + + object_child_foreach_recursive(object_get_root(), + qmp_x_query_rdma_foreach, buf); + + return human_readable_text_from_str(buf); +} + +HumanReadableText *qmp_x_query_ramblock(Error **errp) +{ + g_autoptr(GString) buf = ram_block_format(); + + return human_readable_text_from_str(buf); +} + +static int qmp_x_query_irq_foreach(Object *obj, void *opaque) +{ + InterruptStatsProvider *intc; + InterruptStatsProviderClass *k; + GString *buf = opaque; + + if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { + intc = INTERRUPT_STATS_PROVIDER(obj); + k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); + uint64_t *irq_counts; + unsigned int nb_irqs, i; + if (k->get_statistics && + k->get_statistics(intc, &irq_counts, &nb_irqs)) { + if (nb_irqs > 0) { + g_string_append_printf(buf, "IRQ statistics for %s:\n", + object_get_typename(obj)); + for (i = 0; i < nb_irqs; i++) { + if (irq_counts[i] > 0) { + g_string_append_printf(buf, "%2d: %" PRId64 "\n", i, + irq_counts[i]); + } + } + } + } else { + g_string_append_printf(buf, + "IRQ statistics not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +HumanReadableText *qmp_x_query_irq(Error **errp) +{ + g_autoptr(GString) buf = g_string_new(""); + + object_child_foreach_recursive(object_get_root(), + qmp_x_query_irq_foreach, buf); + + return human_readable_text_from_str(buf); +} diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index e5ab77f6c6..4a8d1e9a15 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -24,7 +24,6 @@ #include "qapi/error.h" #include "qapi/qapi-commands-acpi.h" #include "qapi/qapi-commands-control.h" -#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-stats.h" #include "qapi/type-helpers.h" @@ -42,24 +41,6 @@ NameInfo *qmp_query_name(Error **errp) return info; } -KvmInfo *qmp_query_kvm(Error **errp) -{ - KvmInfo *info = g_malloc0(sizeof(*info)); - - info->enabled = kvm_enabled(); - info->present = accel_find("kvm"); - - return info; -} - -UuidInfo *qmp_query_uuid(Error **errp) -{ - UuidInfo *info = g_malloc0(sizeof(*info)); - - info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); - return info; -} - void qmp_quit(Error **errp) { shutdown_action = SHUTDOWN_ACTION_POWEROFF; @@ -82,16 +63,6 @@ void qmp_stop(Error **errp) } } -void qmp_system_reset(Error **errp) -{ - qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); -} - -void qmp_system_powerdown(Error **errp) -{ - qemu_system_powerdown_request(); -} - void qmp_cont(Error **errp) { BlockBackend *blk; @@ -145,17 +116,6 @@ void qmp_cont(Error **errp) } } -void qmp_system_wakeup(Error **errp) -{ - if (!qemu_wakeup_suspend_enabled()) { - error_setg(errp, - "wake-up from suspend is not supported by this guest"); - return; - } - - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); -} - void qmp_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) @@ -196,11 +156,6 @@ void qmp_add_client(const char *protocol, const char *fdname, } } -MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp) -{ - return qmp_memory_device_list(); -} - ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) { bool ambig; @@ -220,101 +175,6 @@ ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) return head; } -MemoryInfo *qmp_query_memory_size_summary(Error **errp) -{ - MemoryInfo *mem_info = g_new0(MemoryInfo, 1); - MachineState *ms = MACHINE(qdev_get_machine()); - - mem_info->base_memory = ms->ram_size; - - mem_info->plugged_memory = get_plugged_memory_size(); - mem_info->has_plugged_memory = - mem_info->plugged_memory != (uint64_t)-1; - - return mem_info; -} - -static int qmp_x_query_rdma_foreach(Object *obj, void *opaque) -{ - RdmaProvider *rdma; - RdmaProviderClass *k; - GString *buf = opaque; - - if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) { - rdma = RDMA_PROVIDER(obj); - k = RDMA_PROVIDER_GET_CLASS(obj); - if (k->format_statistics) { - k->format_statistics(rdma, buf); - } else { - g_string_append_printf(buf, - "RDMA statistics not available for %s.\n", - object_get_typename(obj)); - } - } - - return 0; -} - -HumanReadableText *qmp_x_query_rdma(Error **errp) -{ - g_autoptr(GString) buf = g_string_new(""); - - object_child_foreach_recursive(object_get_root(), - qmp_x_query_rdma_foreach, buf); - - return human_readable_text_from_str(buf); -} - -HumanReadableText *qmp_x_query_ramblock(Error **errp) -{ - g_autoptr(GString) buf = ram_block_format(); - - return human_readable_text_from_str(buf); -} - -static int qmp_x_query_irq_foreach(Object *obj, void *opaque) -{ - InterruptStatsProvider *intc; - InterruptStatsProviderClass *k; - GString *buf = opaque; - - if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { - intc = INTERRUPT_STATS_PROVIDER(obj); - k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); - uint64_t *irq_counts; - unsigned int nb_irqs, i; - if (k->get_statistics && - k->get_statistics(intc, &irq_counts, &nb_irqs)) { - if (nb_irqs > 0) { - g_string_append_printf(buf, "IRQ statistics for %s:\n", - object_get_typename(obj)); - for (i = 0; i < nb_irqs; i++) { - if (irq_counts[i] > 0) { - g_string_append_printf(buf, "%2d: %" PRId64 "\n", i, - irq_counts[i]); - } - } - } - } else { - g_string_append_printf(buf, - "IRQ statistics not available for %s.\n", - object_get_typename(obj)); - } - } - - return 0; -} - -HumanReadableText *qmp_x_query_irq(Error **errp) -{ - g_autoptr(GString) buf = g_string_new(""); - - object_child_foreach_recursive(object_get_root(), - qmp_x_query_irq_foreach, buf); - - return human_readable_text_from_str(buf); -} - typedef struct StatsCallbacks { StatsProvider provider; StatRetrieveFunc *stats_cb; From 85ea9dfedd1650782588063418d8530bd8042932 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:24 +0100 Subject: [PATCH 447/814] machine: Move HMP commands from monitor/ to hw/core/ This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "Machine core". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-11-armbru@redhat.com> --- hw/core/machine-hmp-cmds.c | 208 ++++++++++++++++++++++++++++++++++++ monitor/hmp-cmds.c | 209 ------------------------------------- 2 files changed, 208 insertions(+), 209 deletions(-) diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index a1a51e9778..c3e55ef9e9 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -134,3 +134,211 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict) qapi_free_MemdevList(memdev_list); hmp_handle_error(mon, err); } + +void hmp_info_kvm(Monitor *mon, const QDict *qdict) +{ + KvmInfo *info; + + info = qmp_query_kvm(NULL); + monitor_printf(mon, "kvm support: "); + if (info->present) { + monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled"); + } else { + monitor_printf(mon, "not compiled\n"); + } + + qapi_free_KvmInfo(info); +} + +void hmp_info_uuid(Monitor *mon, const QDict *qdict) +{ + UuidInfo *info; + + info = qmp_query_uuid(NULL); + monitor_printf(mon, "%s\n", info->UUID); + qapi_free_UuidInfo(info); +} + +void hmp_info_balloon(Monitor *mon, const QDict *qdict) +{ + BalloonInfo *info; + Error *err = NULL; + + info = qmp_query_balloon(&err); + if (hmp_handle_error(mon, err)) { + return; + } + + monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20); + + qapi_free_BalloonInfo(info); +} + +void hmp_system_reset(Monitor *mon, const QDict *qdict) +{ + qmp_system_reset(NULL); +} + +void hmp_system_powerdown(Monitor *mon, const QDict *qdict) +{ + qmp_system_powerdown(NULL); +} + +void hmp_memsave(Monitor *mon, const QDict *qdict) +{ + uint32_t size = qdict_get_int(qdict, "size"); + const char *filename = qdict_get_str(qdict, "filename"); + uint64_t addr = qdict_get_int(qdict, "val"); + Error *err = NULL; + int cpu_index = monitor_get_cpu_index(mon); + + if (cpu_index < 0) { + monitor_printf(mon, "No CPU available\n"); + return; + } + + qmp_memsave(addr, size, filename, true, cpu_index, &err); + hmp_handle_error(mon, err); +} + +void hmp_pmemsave(Monitor *mon, const QDict *qdict) +{ + uint32_t size = qdict_get_int(qdict, "size"); + const char *filename = qdict_get_str(qdict, "filename"); + uint64_t addr = qdict_get_int(qdict, "val"); + Error *err = NULL; + + qmp_pmemsave(addr, size, filename, &err); + hmp_handle_error(mon, err); +} + +void hmp_system_wakeup(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qmp_system_wakeup(&err); + hmp_handle_error(mon, err); +} + +void hmp_nmi(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qmp_inject_nmi(&err); + hmp_handle_error(mon, err); +} + +void hmp_balloon(Monitor *mon, const QDict *qdict) +{ + int64_t value = qdict_get_int(qdict, "value"); + Error *err = NULL; + + qmp_balloon(value, &err); + hmp_handle_error(mon, err); +} + +void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err); + MemoryDeviceInfoList *info; + VirtioPMEMDeviceInfo *vpi; + VirtioMEMDeviceInfo *vmi; + MemoryDeviceInfo *value; + PCDIMMDeviceInfo *di; + SgxEPCDeviceInfo *se; + + for (info = info_list; info; info = info->next) { + value = info->value; + + if (value) { + switch (value->type) { + case MEMORY_DEVICE_INFO_KIND_DIMM: + case MEMORY_DEVICE_INFO_KIND_NVDIMM: + di = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ? + value->u.dimm.data : value->u.nvdimm.data; + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_str(value->type), + di->id ? di->id : ""); + monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr); + monitor_printf(mon, " slot: %" PRId64 "\n", di->slot); + monitor_printf(mon, " node: %" PRId64 "\n", di->node); + monitor_printf(mon, " size: %" PRIu64 "\n", di->size); + monitor_printf(mon, " memdev: %s\n", di->memdev); + monitor_printf(mon, " hotplugged: %s\n", + di->hotplugged ? "true" : "false"); + monitor_printf(mon, " hotpluggable: %s\n", + di->hotpluggable ? "true" : "false"); + break; + case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM: + vpi = value->u.virtio_pmem.data; + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_str(value->type), + vpi->id ? vpi->id : ""); + monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vpi->memaddr); + monitor_printf(mon, " size: %" PRIu64 "\n", vpi->size); + monitor_printf(mon, " memdev: %s\n", vpi->memdev); + break; + case MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM: + vmi = value->u.virtio_mem.data; + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_str(value->type), + vmi->id ? vmi->id : ""); + monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vmi->memaddr); + monitor_printf(mon, " node: %" PRId64 "\n", vmi->node); + monitor_printf(mon, " requested-size: %" PRIu64 "\n", + vmi->requested_size); + monitor_printf(mon, " size: %" PRIu64 "\n", vmi->size); + monitor_printf(mon, " max-size: %" PRIu64 "\n", vmi->max_size); + monitor_printf(mon, " block-size: %" PRIu64 "\n", + vmi->block_size); + monitor_printf(mon, " memdev: %s\n", vmi->memdev); + break; + case MEMORY_DEVICE_INFO_KIND_SGX_EPC: + se = value->u.sgx_epc.data; + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_str(value->type), + se->id ? se->id : ""); + monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", se->memaddr); + monitor_printf(mon, " size: %" PRIu64 "\n", se->size); + monitor_printf(mon, " node: %" PRId64 "\n", se->node); + monitor_printf(mon, " memdev: %s\n", se->memdev); + break; + default: + g_assert_not_reached(); + } + } + } + + qapi_free_MemoryDeviceInfoList(info_list); + hmp_handle_error(mon, err); +} + +void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + GuidInfo *info = qmp_query_vm_generation_id(&err); + if (info) { + monitor_printf(mon, "%s\n", info->guid); + } + hmp_handle_error(mon, err); + qapi_free_GuidInfo(info); +} + +void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + MemoryInfo *info = qmp_query_memory_size_summary(&err); + if (info) { + monitor_printf(mon, "base memory: %" PRIu64 "\n", + info->base_memory); + + if (info->has_plugged_memory) { + monitor_printf(mon, "plugged memory: %" PRIu64 "\n", + info->plugged_memory); + } + + qapi_free_MemoryInfo(info); + } + hmp_handle_error(mon, err); +} diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c8ed59c281..1e41381e77 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -26,7 +26,6 @@ #include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-control.h" -#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-net.h" @@ -108,21 +107,6 @@ void hmp_info_version(Monitor *mon, const QDict *qdict) qapi_free_VersionInfo(info); } -void hmp_info_kvm(Monitor *mon, const QDict *qdict) -{ - KvmInfo *info; - - info = qmp_query_kvm(NULL); - monitor_printf(mon, "kvm support: "); - if (info->present) { - monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled"); - } else { - monitor_printf(mon, "not compiled\n"); - } - - qapi_free_KvmInfo(info); -} - void hmp_info_status(Monitor *mon, const QDict *qdict) { StatusInfo *info; @@ -142,15 +126,6 @@ void hmp_info_status(Monitor *mon, const QDict *qdict) qapi_free_StatusInfo(info); } -void hmp_info_uuid(Monitor *mon, const QDict *qdict) -{ - UuidInfo *info; - - info = qmp_query_uuid(NULL); - monitor_printf(mon, "%s\n", info->UUID); - qapi_free_UuidInfo(info); -} - void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; @@ -469,21 +444,6 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) qapi_free_MigrationParameters(params); } -void hmp_info_balloon(Monitor *mon, const QDict *qdict) -{ - BalloonInfo *info; - Error *err = NULL; - - info = qmp_query_balloon(&err); - if (hmp_handle_error(mon, err)) { - return; - } - - monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20); - - qapi_free_BalloonInfo(info); -} - static int hmp_info_pic_foreach(Object *obj, void *opaque) { InterruptStatsProvider *intc; @@ -598,16 +558,6 @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict) } } -void hmp_system_reset(Monitor *mon, const QDict *qdict) -{ - qmp_system_reset(NULL); -} - -void hmp_system_powerdown(Monitor *mon, const QDict *qdict) -{ - qmp_system_powerdown(NULL); -} - void hmp_exit_preconfig(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -628,34 +578,6 @@ void hmp_cpu(Monitor *mon, const QDict *qdict) } } -void hmp_memsave(Monitor *mon, const QDict *qdict) -{ - uint32_t size = qdict_get_int(qdict, "size"); - const char *filename = qdict_get_str(qdict, "filename"); - uint64_t addr = qdict_get_int(qdict, "val"); - Error *err = NULL; - int cpu_index = monitor_get_cpu_index(mon); - - if (cpu_index < 0) { - monitor_printf(mon, "No CPU available\n"); - return; - } - - qmp_memsave(addr, size, filename, true, cpu_index, &err); - hmp_handle_error(mon, err); -} - -void hmp_pmemsave(Monitor *mon, const QDict *qdict) -{ - uint32_t size = qdict_get_int(qdict, "size"); - const char *filename = qdict_get_str(qdict, "filename"); - uint64_t addr = qdict_get_int(qdict, "val"); - Error *err = NULL; - - qmp_pmemsave(addr, size, filename, &err); - hmp_handle_error(mon, err); -} - void hmp_cont(Monitor *mon, const QDict *qdict) { Error *err = NULL; @@ -664,22 +586,6 @@ void hmp_cont(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_system_wakeup(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - qmp_system_wakeup(&err); - hmp_handle_error(mon, err); -} - -void hmp_nmi(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - qmp_inject_nmi(&err); - hmp_handle_error(mon, err); -} - void hmp_set_link(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_str(qdict, "name"); @@ -690,15 +596,6 @@ void hmp_set_link(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_balloon(Monitor *mon, const QDict *qdict) -{ - int64_t value = qdict_get_int(qdict, "value"); - Error *err = NULL; - - qmp_balloon(value, &err); - hmp_handle_error(mon, err); -} - void hmp_loadvm(Monitor *mon, const QDict *qdict) { int saved_vm_running = runstate_is_running(); @@ -1193,83 +1090,6 @@ void hmp_object_del(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err); - MemoryDeviceInfoList *info; - VirtioPMEMDeviceInfo *vpi; - VirtioMEMDeviceInfo *vmi; - MemoryDeviceInfo *value; - PCDIMMDeviceInfo *di; - SgxEPCDeviceInfo *se; - - for (info = info_list; info; info = info->next) { - value = info->value; - - if (value) { - switch (value->type) { - case MEMORY_DEVICE_INFO_KIND_DIMM: - case MEMORY_DEVICE_INFO_KIND_NVDIMM: - di = value->type == MEMORY_DEVICE_INFO_KIND_DIMM ? - value->u.dimm.data : value->u.nvdimm.data; - monitor_printf(mon, "Memory device [%s]: \"%s\"\n", - MemoryDeviceInfoKind_str(value->type), - di->id ? di->id : ""); - monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr); - monitor_printf(mon, " slot: %" PRId64 "\n", di->slot); - monitor_printf(mon, " node: %" PRId64 "\n", di->node); - monitor_printf(mon, " size: %" PRIu64 "\n", di->size); - monitor_printf(mon, " memdev: %s\n", di->memdev); - monitor_printf(mon, " hotplugged: %s\n", - di->hotplugged ? "true" : "false"); - monitor_printf(mon, " hotpluggable: %s\n", - di->hotpluggable ? "true" : "false"); - break; - case MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM: - vpi = value->u.virtio_pmem.data; - monitor_printf(mon, "Memory device [%s]: \"%s\"\n", - MemoryDeviceInfoKind_str(value->type), - vpi->id ? vpi->id : ""); - monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vpi->memaddr); - monitor_printf(mon, " size: %" PRIu64 "\n", vpi->size); - monitor_printf(mon, " memdev: %s\n", vpi->memdev); - break; - case MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM: - vmi = value->u.virtio_mem.data; - monitor_printf(mon, "Memory device [%s]: \"%s\"\n", - MemoryDeviceInfoKind_str(value->type), - vmi->id ? vmi->id : ""); - monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", vmi->memaddr); - monitor_printf(mon, " node: %" PRId64 "\n", vmi->node); - monitor_printf(mon, " requested-size: %" PRIu64 "\n", - vmi->requested_size); - monitor_printf(mon, " size: %" PRIu64 "\n", vmi->size); - monitor_printf(mon, " max-size: %" PRIu64 "\n", vmi->max_size); - monitor_printf(mon, " block-size: %" PRIu64 "\n", - vmi->block_size); - monitor_printf(mon, " memdev: %s\n", vmi->memdev); - break; - case MEMORY_DEVICE_INFO_KIND_SGX_EPC: - se = value->u.sgx_epc.data; - monitor_printf(mon, "Memory device [%s]: \"%s\"\n", - MemoryDeviceInfoKind_str(value->type), - se->id ? se->id : ""); - monitor_printf(mon, " memaddr: 0x%" PRIx64 "\n", se->memaddr); - monitor_printf(mon, " size: %" PRIu64 "\n", se->size); - monitor_printf(mon, " node: %" PRId64 "\n", se->node); - monitor_printf(mon, " memdev: %s\n", se->memdev); - break; - default: - g_assert_not_reached(); - } - } - } - - qapi_free_MemoryDeviceInfoList(info_list); - hmp_handle_error(mon, err); -} - void hmp_info_iothreads(Monitor *mon, const QDict *qdict) { IOThreadInfoList *info_list = qmp_query_iothreads(NULL); @@ -1585,35 +1405,6 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) qapi_free_RockerOfDpaGroupList(list); } -void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - GuidInfo *info = qmp_query_vm_generation_id(&err); - if (info) { - monitor_printf(mon, "%s\n", info->guid); - } - hmp_handle_error(mon, err); - qapi_free_GuidInfo(info); -} - -void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - MemoryInfo *info = qmp_query_memory_size_summary(&err); - if (info) { - monitor_printf(mon, "base memory: %" PRIu64 "\n", - info->base_memory); - - if (info->has_plugged_memory) { - monitor_printf(mon, "plugged memory: %" PRIu64 "\n", - info->plugged_memory); - } - - qapi_free_MemoryInfo(info); - } - hmp_handle_error(mon, err); -} - static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) { const char *unit = NULL; From cffaca0fab7ccb955c0e498c5132b801844d2c41 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:25 +0100 Subject: [PATCH 448/814] qom: Move HMP commands from monitor/ to qom/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "QOM". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-12-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- monitor/hmp-cmds.c | 19 ------------- monitor/misc.c | 49 --------------------------------- qom/qom-hmp-cmds.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 1e41381e77..4fe2aaebcd 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -40,7 +40,6 @@ #include "qapi/qmp/qerror.h" #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" -#include "qom/object_interfaces.h" #include "qemu/cutils.h" #include "qemu/error-report.h" #include "hw/core/cpu.h" @@ -1054,15 +1053,6 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_object_add(Monitor *mon, const QDict *qdict) -{ - const char *options = qdict_get_str(qdict, "object"); - Error *err = NULL; - - user_creatable_add_from_str(options, &err); - hmp_handle_error(mon, err); -} - void hmp_getfd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); @@ -1081,15 +1071,6 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_object_del(Monitor *mon, const QDict *qdict) -{ - const char *id = qdict_get_str(qdict, "id"); - Error *err = NULL; - - user_creatable_del(id, &err); - hmp_handle_error(mon, err); -} - void hmp_info_iothreads(Monitor *mon, const QDict *qdict) { IOThreadInfoList *info_list = qmp_query_iothreads(NULL); diff --git a/monitor/misc.c b/monitor/misc.c index 2a6bc13e7f..0cf2518ce1 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -38,7 +38,6 @@ #include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qom/object_interfaces.h" #include "monitor/hmp-target.h" #include "monitor/hmp.h" #include "exec/address-spaces.h" @@ -48,7 +47,6 @@ #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-qom.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-init-commands.h" @@ -1310,30 +1308,6 @@ void device_add_completion(ReadLineState *rs, int nb_args, const char *str) g_slist_free(list); } -void object_add_completion(ReadLineState *rs, int nb_args, const char *str) -{ - GSList *list, *elt; - size_t len; - - if (nb_args != 2) { - return; - } - - len = strlen(str); - readline_set_completion_index(rs, len); - list = elt = object_class_get_list(TYPE_USER_CREATABLE, false); - while (elt) { - const char *name; - - name = object_class_get_name(OBJECT_CLASS(elt->data)); - if (strcmp(name, TYPE_USER_CREATABLE)) { - readline_add_completion_of(rs, str, name); - } - elt = elt->next; - } - g_slist_free(list); -} - static int qdev_add_hotpluggable_device(Object *obj, void *opaque) { GSList **list = opaque; @@ -1391,29 +1365,6 @@ void device_del_completion(ReadLineState *rs, int nb_args, const char *str) peripheral_device_del_completion(rs, str); } -void object_del_completion(ReadLineState *rs, int nb_args, const char *str) -{ - ObjectPropertyInfoList *list, *start; - size_t len; - - if (nb_args != 2) { - return; - } - len = strlen(str); - readline_set_completion_index(rs, len); - - start = list = qmp_qom_list("/objects", NULL); - while (list) { - ObjectPropertyInfo *info = list->value; - - if (!strncmp(info->type, "child<", 5)) { - readline_add_completion_of(rs, str, info->name); - } - list = list->next; - } - qapi_free_ObjectPropertyInfoList(start); -} - void set_link_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; diff --git a/qom/qom-hmp-cmds.c b/qom/qom-hmp-cmds.c index 453fbfeabc..6e3a2175a4 100644 --- a/qom/qom-hmp-cmds.c +++ b/qom/qom-hmp-cmds.c @@ -13,7 +13,9 @@ #include "qapi/qapi-commands-qom.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" +#include "qemu/readline.h" #include "qom/object.h" +#include "qom/object_interfaces.h" void hmp_qom_list(Monitor *mon, const QDict *qdict) { @@ -150,3 +152,68 @@ void hmp_info_qom_tree(Monitor *mon, const QDict *dict) } print_qom_composition(mon, obj, 0); } + +void hmp_object_add(Monitor *mon, const QDict *qdict) +{ + const char *options = qdict_get_str(qdict, "object"); + Error *err = NULL; + + user_creatable_add_from_str(options, &err); + hmp_handle_error(mon, err); +} + +void hmp_object_del(Monitor *mon, const QDict *qdict) +{ + const char *id = qdict_get_str(qdict, "id"); + Error *err = NULL; + + user_creatable_del(id, &err); + hmp_handle_error(mon, err); +} + +void object_add_completion(ReadLineState *rs, int nb_args, const char *str) +{ + GSList *list, *elt; + size_t len; + + if (nb_args != 2) { + return; + } + + len = strlen(str); + readline_set_completion_index(rs, len); + list = elt = object_class_get_list(TYPE_USER_CREATABLE, false); + while (elt) { + const char *name; + + name = object_class_get_name(OBJECT_CLASS(elt->data)); + if (strcmp(name, TYPE_USER_CREATABLE)) { + readline_add_completion_of(rs, str, name); + } + elt = elt->next; + } + g_slist_free(list); +} + +void object_del_completion(ReadLineState *rs, int nb_args, const char *str) +{ + ObjectPropertyInfoList *list, *start; + size_t len; + + if (nb_args != 2) { + return; + } + len = strlen(str); + readline_set_completion_index(rs, len); + + start = list = qmp_qom_list("/objects", NULL); + while (list) { + ObjectPropertyInfo *info = list->value; + + if (!strncmp(info->type, "child<", 5)) { + readline_add_completion_of(rs, str, info->name); + } + list = list->next; + } + qapi_free_ObjectPropertyInfoList(start); +} From fa1d2f8f635f2e3d7a7269283cc0ff81ea6f2031 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:26 +0100 Subject: [PATCH 449/814] block: Factor out hmp_change_medium(), and move to block/monitor/ Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-13-armbru@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Stefan Berger --- block/monitor/block-hmp-cmds.c | 21 +++++++++++++++++++++ include/monitor/hmp.h | 3 +++ monitor/hmp-cmds.c | 17 +---------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index 0ff7c84039..ae624ab575 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -1005,3 +1005,24 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) g_free(sn_tab); g_free(global_snapshots); } + +void hmp_change_medium(Monitor *mon, const char *device, const char *target, + const char *arg, const char *read_only, bool force, + Error **errp) +{ + ERRP_GUARD(); + BlockdevChangeReadOnlyMode read_only_mode = 0; + + if (read_only) { + read_only_mode = + qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup, + read_only, + BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, errp); + if (*errp) { + return; + } + } + + qmp_blockdev_change_medium(device, NULL, target, arg, true, force, + !!read_only, read_only_mode, errp); +} diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 58ed1bec62..6fafa7ffb4 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -78,6 +78,9 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target, const char *arg, const char *read_only, bool force, Error **errp); #endif +void hmp_change_medium(Monitor *mon, const char *device, const char *target, + const char *arg, const char *read_only, bool force, + Error **errp); void hmp_migrate(Monitor *mon, const QDict *qdict); void hmp_device_add(Monitor *mon, const QDict *qdict); void hmp_device_del(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 4fe2aaebcd..bed75af656 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -24,7 +24,6 @@ #include "qapi/error.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-builtin-visit.h" -#include "qapi/qapi-commands-block.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" @@ -916,7 +915,6 @@ void hmp_change(Monitor *mon, const QDict *qdict) const char *arg = qdict_get_try_str(qdict, "arg"); const char *read_only = qdict_get_try_str(qdict, "read-only-mode"); bool force = qdict_get_try_bool(qdict, "force", false); - BlockdevChangeReadOnlyMode read_only_mode = 0; Error *err = NULL; #ifdef CONFIG_VNC @@ -925,22 +923,9 @@ void hmp_change(Monitor *mon, const QDict *qdict) } else #endif { - if (read_only) { - read_only_mode = - qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup, - read_only, - BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err); - if (err) { - goto end; - } - } - - qmp_blockdev_change_medium(device, NULL, target, arg, true, force, - !!read_only, read_only_mode, - &err); + hmp_change_medium(mon, device, target, arg, read_only, force, &err); } -end: hmp_handle_error(mon, err); } From 52cafcea43db82a52596d37b347b84e3c9ac8452 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:27 +0100 Subject: [PATCH 450/814] rocker: Move HMP commands from monitor to hw/net/rocker/ This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "Rocker" and "Network devices". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-14-armbru@redhat.com> --- hw/net/meson.build | 1 + hw/net/rocker/rocker-hmp-cmds.c | 316 ++++++++++++++++++++++++++++++++ monitor/hmp-cmds.c | 297 ------------------------------ 3 files changed, 317 insertions(+), 297 deletions(-) create mode 100644 hw/net/rocker/rocker-hmp-cmds.c diff --git a/hw/net/meson.build b/hw/net/meson.build index ebac261542..4285145715 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -68,5 +68,6 @@ softmmu_ss.add(when: 'CONFIG_ROCKER', if_true: files( 'rocker/rocker_world.c', ), if_false: files('rocker/qmp-norocker.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('rocker/qmp-norocker.c')) +softmmu_ss.add(files('rocker/rocker-hmp-cmds.c')) subdir('can') diff --git a/hw/net/rocker/rocker-hmp-cmds.c b/hw/net/rocker/rocker-hmp-cmds.c new file mode 100644 index 0000000000..197c6e28dc --- /dev/null +++ b/hw/net/rocker/rocker-hmp-cmds.c @@ -0,0 +1,316 @@ +/* + * Human Monitor Interface commands + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "net/eth.h" +#include "qapi/qapi-commands-rocker.h" +#include "qapi/qmp/qdict.h" + +void hmp_rocker(Monitor *mon, const QDict *qdict) +{ + const char *name = qdict_get_str(qdict, "name"); + RockerSwitch *rocker; + Error *err = NULL; + + rocker = qmp_query_rocker(name, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + monitor_printf(mon, "name: %s\n", rocker->name); + monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id); + monitor_printf(mon, "ports: %d\n", rocker->ports); + + qapi_free_RockerSwitch(rocker); +} + +void hmp_rocker_ports(Monitor *mon, const QDict *qdict) +{ + RockerPortList *list, *port; + const char *name = qdict_get_str(qdict, "name"); + Error *err = NULL; + + list = qmp_query_rocker_ports(name, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + monitor_printf(mon, " ena/ speed/ auto\n"); + monitor_printf(mon, " port link duplex neg?\n"); + + for (port = list; port; port = port->next) { + monitor_printf(mon, "%10s %-4s %-3s %2s %s\n", + port->value->name, + port->value->enabled ? port->value->link_up ? + "up" : "down" : "!ena", + port->value->speed == 10000 ? "10G" : "??", + port->value->duplex ? "FD" : "HD", + port->value->autoneg ? "Yes" : "No"); + } + + qapi_free_RockerPortList(list); +} + +void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) +{ + RockerOfDpaFlowList *list, *info; + const char *name = qdict_get_str(qdict, "name"); + uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); + Error *err = NULL; + + list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + monitor_printf(mon, "prio tbl hits key(mask) --> actions\n"); + + for (info = list; info; info = info->next) { + RockerOfDpaFlow *flow = info->value; + RockerOfDpaFlowKey *key = flow->key; + RockerOfDpaFlowMask *mask = flow->mask; + RockerOfDpaFlowAction *action = flow->action; + + if (flow->hits) { + monitor_printf(mon, "%-4d %-3d %-4" PRIu64, + key->priority, key->tbl_id, flow->hits); + } else { + monitor_printf(mon, "%-4d %-3d ", + key->priority, key->tbl_id); + } + + if (key->has_in_pport) { + monitor_printf(mon, " pport %d", key->in_pport); + if (mask->has_in_pport) { + monitor_printf(mon, "(0x%x)", mask->in_pport); + } + } + + if (key->has_vlan_id) { + monitor_printf(mon, " vlan %d", + key->vlan_id & VLAN_VID_MASK); + if (mask->has_vlan_id) { + monitor_printf(mon, "(0x%x)", mask->vlan_id); + } + } + + if (key->has_tunnel_id) { + monitor_printf(mon, " tunnel %d", key->tunnel_id); + if (mask->has_tunnel_id) { + monitor_printf(mon, "(0x%x)", mask->tunnel_id); + } + } + + if (key->has_eth_type) { + switch (key->eth_type) { + case 0x0806: + monitor_printf(mon, " ARP"); + break; + case 0x0800: + monitor_printf(mon, " IP"); + break; + case 0x86dd: + monitor_printf(mon, " IPv6"); + break; + case 0x8809: + monitor_printf(mon, " LACP"); + break; + case 0x88cc: + monitor_printf(mon, " LLDP"); + break; + default: + monitor_printf(mon, " eth type 0x%04x", key->eth_type); + break; + } + } + + if (key->eth_src) { + if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) && + mask->eth_src && + (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " src "); + } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) && + mask->eth_src && + (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " src "); + } else { + monitor_printf(mon, " src %s", key->eth_src); + if (mask->eth_src) { + monitor_printf(mon, "(%s)", mask->eth_src); + } + } + } + + if (key->eth_dst) { + if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) && + mask->eth_dst && + (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " dst "); + } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) && + mask->eth_dst && + (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { + monitor_printf(mon, " dst "); + } else { + monitor_printf(mon, " dst %s", key->eth_dst); + if (mask->eth_dst) { + monitor_printf(mon, "(%s)", mask->eth_dst); + } + } + } + + if (key->has_ip_proto) { + monitor_printf(mon, " proto %d", key->ip_proto); + if (mask->has_ip_proto) { + monitor_printf(mon, "(0x%x)", mask->ip_proto); + } + } + + if (key->has_ip_tos) { + monitor_printf(mon, " TOS %d", key->ip_tos); + if (mask->has_ip_tos) { + monitor_printf(mon, "(0x%x)", mask->ip_tos); + } + } + + if (key->ip_dst) { + monitor_printf(mon, " dst %s", key->ip_dst); + } + + if (action->has_goto_tbl || action->has_group_id || + action->has_new_vlan_id) { + monitor_printf(mon, " -->"); + } + + if (action->has_new_vlan_id) { + monitor_printf(mon, " apply new vlan %d", + ntohs(action->new_vlan_id)); + } + + if (action->has_group_id) { + monitor_printf(mon, " write group 0x%08x", action->group_id); + } + + if (action->has_goto_tbl) { + monitor_printf(mon, " goto tbl %d", action->goto_tbl); + } + + monitor_printf(mon, "\n"); + } + + qapi_free_RockerOfDpaFlowList(list); +} + +void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) +{ + RockerOfDpaGroupList *list, *g; + const char *name = qdict_get_str(qdict, "name"); + uint8_t type = qdict_get_try_int(qdict, "type", 9); + Error *err = NULL; + + list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + monitor_printf(mon, "id (decode) --> buckets\n"); + + for (g = list; g; g = g->next) { + RockerOfDpaGroup *group = g->value; + bool set = false; + + monitor_printf(mon, "0x%08x", group->id); + + monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" : + group->type == 1 ? "L2 rewrite" : + group->type == 2 ? "L3 unicast" : + group->type == 3 ? "L2 multicast" : + group->type == 4 ? "L2 flood" : + group->type == 5 ? "L3 interface" : + group->type == 6 ? "L3 multicast" : + group->type == 7 ? "L3 ECMP" : + group->type == 8 ? "L2 overlay" : + "unknown"); + + if (group->has_vlan_id) { + monitor_printf(mon, " vlan %d", group->vlan_id); + } + + if (group->has_pport) { + monitor_printf(mon, " pport %d", group->pport); + } + + if (group->has_index) { + monitor_printf(mon, " index %d", group->index); + } + + monitor_printf(mon, ") -->"); + + if (group->has_set_vlan_id && group->set_vlan_id) { + set = true; + monitor_printf(mon, " set vlan %d", + group->set_vlan_id & VLAN_VID_MASK); + } + + if (group->set_eth_src) { + if (!set) { + set = true; + monitor_printf(mon, " set"); + } + monitor_printf(mon, " src %s", group->set_eth_src); + } + + if (group->set_eth_dst) { + if (!set) { + monitor_printf(mon, " set"); + } + monitor_printf(mon, " dst %s", group->set_eth_dst); + } + + if (group->has_ttl_check && group->ttl_check) { + monitor_printf(mon, " check TTL"); + } + + if (group->has_group_id && group->group_id) { + monitor_printf(mon, " group id 0x%08x", group->group_id); + } + + if (group->has_pop_vlan && group->pop_vlan) { + monitor_printf(mon, " pop vlan"); + } + + if (group->has_out_pport) { + monitor_printf(mon, " out pport %d", group->out_pport); + } + + if (group->has_group_ids) { + struct uint32List *id; + + monitor_printf(mon, " groups ["); + for (id = group->group_ids; id; id = id->next) { + monitor_printf(mon, "0x%08x", id->value); + if (id->next) { + monitor_printf(mon, ","); + } + } + monitor_printf(mon, "]"); + } + + monitor_printf(mon, "\n"); + } + + qapi_free_RockerOfDpaGroupList(list); +} diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index bed75af656..edb50da1ff 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" #include "monitor/hmp.h" #include "net/net.h" -#include "net/eth.h" #include "sysemu/runstate.h" #include "qemu/sockets.h" #include "qemu/help_option.h" @@ -28,7 +27,6 @@ #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-net.h" -#include "qapi/qapi-commands-rocker.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" @@ -1076,301 +1074,6 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict) qapi_free_IOThreadInfoList(info_list); } -void hmp_rocker(Monitor *mon, const QDict *qdict) -{ - const char *name = qdict_get_str(qdict, "name"); - RockerSwitch *rocker; - Error *err = NULL; - - rocker = qmp_query_rocker(name, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - monitor_printf(mon, "name: %s\n", rocker->name); - monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id); - monitor_printf(mon, "ports: %d\n", rocker->ports); - - qapi_free_RockerSwitch(rocker); -} - -void hmp_rocker_ports(Monitor *mon, const QDict *qdict) -{ - RockerPortList *list, *port; - const char *name = qdict_get_str(qdict, "name"); - Error *err = NULL; - - list = qmp_query_rocker_ports(name, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - monitor_printf(mon, " ena/ speed/ auto\n"); - monitor_printf(mon, " port link duplex neg?\n"); - - for (port = list; port; port = port->next) { - monitor_printf(mon, "%10s %-4s %-3s %2s %s\n", - port->value->name, - port->value->enabled ? port->value->link_up ? - "up" : "down" : "!ena", - port->value->speed == 10000 ? "10G" : "??", - port->value->duplex ? "FD" : "HD", - port->value->autoneg ? "Yes" : "No"); - } - - qapi_free_RockerPortList(list); -} - -void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) -{ - RockerOfDpaFlowList *list, *info; - const char *name = qdict_get_str(qdict, "name"); - uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); - Error *err = NULL; - - list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - monitor_printf(mon, "prio tbl hits key(mask) --> actions\n"); - - for (info = list; info; info = info->next) { - RockerOfDpaFlow *flow = info->value; - RockerOfDpaFlowKey *key = flow->key; - RockerOfDpaFlowMask *mask = flow->mask; - RockerOfDpaFlowAction *action = flow->action; - - if (flow->hits) { - monitor_printf(mon, "%-4d %-3d %-4" PRIu64, - key->priority, key->tbl_id, flow->hits); - } else { - monitor_printf(mon, "%-4d %-3d ", - key->priority, key->tbl_id); - } - - if (key->has_in_pport) { - monitor_printf(mon, " pport %d", key->in_pport); - if (mask->has_in_pport) { - monitor_printf(mon, "(0x%x)", mask->in_pport); - } - } - - if (key->has_vlan_id) { - monitor_printf(mon, " vlan %d", - key->vlan_id & VLAN_VID_MASK); - if (mask->has_vlan_id) { - monitor_printf(mon, "(0x%x)", mask->vlan_id); - } - } - - if (key->has_tunnel_id) { - monitor_printf(mon, " tunnel %d", key->tunnel_id); - if (mask->has_tunnel_id) { - monitor_printf(mon, "(0x%x)", mask->tunnel_id); - } - } - - if (key->has_eth_type) { - switch (key->eth_type) { - case 0x0806: - monitor_printf(mon, " ARP"); - break; - case 0x0800: - monitor_printf(mon, " IP"); - break; - case 0x86dd: - monitor_printf(mon, " IPv6"); - break; - case 0x8809: - monitor_printf(mon, " LACP"); - break; - case 0x88cc: - monitor_printf(mon, " LLDP"); - break; - default: - monitor_printf(mon, " eth type 0x%04x", key->eth_type); - break; - } - } - - if (key->eth_src) { - if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) && - mask->eth_src && - (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { - monitor_printf(mon, " src "); - } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) && - mask->eth_src && - (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { - monitor_printf(mon, " src "); - } else { - monitor_printf(mon, " src %s", key->eth_src); - if (mask->eth_src) { - monitor_printf(mon, "(%s)", mask->eth_src); - } - } - } - - if (key->eth_dst) { - if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) && - mask->eth_dst && - (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { - monitor_printf(mon, " dst "); - } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) && - mask->eth_dst && - (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { - monitor_printf(mon, " dst "); - } else { - monitor_printf(mon, " dst %s", key->eth_dst); - if (mask->eth_dst) { - monitor_printf(mon, "(%s)", mask->eth_dst); - } - } - } - - if (key->has_ip_proto) { - monitor_printf(mon, " proto %d", key->ip_proto); - if (mask->has_ip_proto) { - monitor_printf(mon, "(0x%x)", mask->ip_proto); - } - } - - if (key->has_ip_tos) { - monitor_printf(mon, " TOS %d", key->ip_tos); - if (mask->has_ip_tos) { - monitor_printf(mon, "(0x%x)", mask->ip_tos); - } - } - - if (key->ip_dst) { - monitor_printf(mon, " dst %s", key->ip_dst); - } - - if (action->has_goto_tbl || action->has_group_id || - action->has_new_vlan_id) { - monitor_printf(mon, " -->"); - } - - if (action->has_new_vlan_id) { - monitor_printf(mon, " apply new vlan %d", - ntohs(action->new_vlan_id)); - } - - if (action->has_group_id) { - monitor_printf(mon, " write group 0x%08x", action->group_id); - } - - if (action->has_goto_tbl) { - monitor_printf(mon, " goto tbl %d", action->goto_tbl); - } - - monitor_printf(mon, "\n"); - } - - qapi_free_RockerOfDpaFlowList(list); -} - -void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) -{ - RockerOfDpaGroupList *list, *g; - const char *name = qdict_get_str(qdict, "name"); - uint8_t type = qdict_get_try_int(qdict, "type", 9); - Error *err = NULL; - - list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - monitor_printf(mon, "id (decode) --> buckets\n"); - - for (g = list; g; g = g->next) { - RockerOfDpaGroup *group = g->value; - bool set = false; - - monitor_printf(mon, "0x%08x", group->id); - - monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" : - group->type == 1 ? "L2 rewrite" : - group->type == 2 ? "L3 unicast" : - group->type == 3 ? "L2 multicast" : - group->type == 4 ? "L2 flood" : - group->type == 5 ? "L3 interface" : - group->type == 6 ? "L3 multicast" : - group->type == 7 ? "L3 ECMP" : - group->type == 8 ? "L2 overlay" : - "unknown"); - - if (group->has_vlan_id) { - monitor_printf(mon, " vlan %d", group->vlan_id); - } - - if (group->has_pport) { - monitor_printf(mon, " pport %d", group->pport); - } - - if (group->has_index) { - monitor_printf(mon, " index %d", group->index); - } - - monitor_printf(mon, ") -->"); - - if (group->has_set_vlan_id && group->set_vlan_id) { - set = true; - monitor_printf(mon, " set vlan %d", - group->set_vlan_id & VLAN_VID_MASK); - } - - if (group->set_eth_src) { - if (!set) { - set = true; - monitor_printf(mon, " set"); - } - monitor_printf(mon, " src %s", group->set_eth_src); - } - - if (group->set_eth_dst) { - if (!set) { - monitor_printf(mon, " set"); - } - monitor_printf(mon, " dst %s", group->set_eth_dst); - } - - if (group->has_ttl_check && group->ttl_check) { - monitor_printf(mon, " check TTL"); - } - - if (group->has_group_id && group->group_id) { - monitor_printf(mon, " group id 0x%08x", group->group_id); - } - - if (group->has_pop_vlan && group->pop_vlan) { - monitor_printf(mon, " pop vlan"); - } - - if (group->has_out_pport) { - monitor_printf(mon, " out pport %d", group->out_pport); - } - - if (group->has_group_ids) { - struct uint32List *id; - - monitor_printf(mon, " groups ["); - for (id = group->group_ids; id; id = id->next) { - monitor_printf(mon, "0x%08x", id->value); - if (id->next) { - monitor_printf(mon, ","); - } - } - monitor_printf(mon, "]"); - } - - monitor_printf(mon, "\n"); - } - - qapi_free_RockerOfDpaGroupList(list); -} - static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) { const char *unit = NULL; From 0d79271b5702d27736fd081d8994e857ae8b5db5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:28 +0100 Subject: [PATCH 451/814] hmp: Rewrite strlist_from_comma_list() as hmp_split_at_comma() Use g_strsplit() for the actual splitting. Give external linkage, so the next commit can move one of its users to another source file. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-15-armbru@redhat.com> --- include/monitor/hmp.h | 1 + monitor/hmp-cmds.c | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 6fafa7ffb4..d60d1305b8 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -19,6 +19,7 @@ bool hmp_handle_error(Monitor *mon, Error *err); void hmp_help_cmd(Monitor *mon, const char *name); +strList *hmp_split_at_comma(const char *str); void hmp_info_name(Monitor *mon, const QDict *qdict); void hmp_info_version(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index edb50da1ff..2ca869c2ee 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -54,28 +54,21 @@ bool hmp_handle_error(Monitor *mon, Error *err) } /* - * Produce a strList from a comma separated list. - * A NULL or empty input string return NULL. + * Split @str at comma. + * A null @str defaults to "". */ -static strList *strList_from_comma_list(const char *in) +strList *hmp_split_at_comma(const char *str) { + char **split = g_strsplit(str ?: "", ",", -1); strList *res = NULL; strList **tail = &res; + int i; - while (in && in[0]) { - char *comma = strchr(in, ','); - char *value; - - if (comma) { - value = g_strndup(in, comma - in); - in = comma + 1; /* skip the , */ - } else { - value = g_strdup(in); - in = NULL; - } - QAPI_LIST_APPEND(tail, value); + for (i = 0; split[i]; i++) { + QAPI_LIST_APPEND(tail, split[i]); } + g_free(split); return res; } @@ -632,7 +625,7 @@ void hmp_announce_self(Monitor *mon, const QDict *qdict) migrate_announce_params()); qapi_free_strList(params->interfaces); - params->interfaces = strList_from_comma_list(interfaces_str); + params->interfaces = hmp_split_at_comma(interfaces_str); params->has_interfaces = params->interfaces != NULL; params->id = g_strdup(id); qmp_announce_self(params, NULL); @@ -1234,7 +1227,7 @@ static StatsFilter *stats_filter(StatsTarget target, const char *names, request->provider = provider_idx; if (names && !g_str_equal(names, "*")) { request->has_names = true; - request->names = strList_from_comma_list(names); + request->names = hmp_split_at_comma(names); } QAPI_LIST_PREPEND(request_list, request); } From 2030ca36bf1af79c68a4955ff3bf240ec561ec72 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:29 +0100 Subject: [PATCH 452/814] net: Move HMP commands from monitor to net/ This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Network device backends". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-16-armbru@redhat.com> --- monitor/hmp-cmds.c | 61 ------------------- monitor/misc.c | 56 ------------------ net/meson.build | 1 + net/net-hmp-cmds.c | 142 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 117 deletions(-) create mode 100644 net/net-hmp-cmds.c diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 2ca869c2ee..90259d02d7 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -21,17 +21,14 @@ #include "qemu/help_option.h" #include "monitor/monitor.h" #include "qapi/error.h" -#include "qapi/clone-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-net.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" #include "qapi/qapi-commands-virtio.h" -#include "qapi/qapi-visit-net.h" #include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" @@ -575,16 +572,6 @@ void hmp_cont(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_set_link(Monitor *mon, const QDict *qdict) -{ - const char *name = qdict_get_str(qdict, "name"); - bool up = qdict_get_bool(qdict, "up"); - Error *err = NULL; - - qmp_set_link(name, up, &err); - hmp_handle_error(mon, err); -} - void hmp_loadvm(Monitor *mon, const QDict *qdict) { int saved_vm_running = runstate_is_running(); @@ -617,21 +604,6 @@ void hmp_delvm(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_announce_self(Monitor *mon, const QDict *qdict) -{ - const char *interfaces_str = qdict_get_try_str(qdict, "interfaces"); - const char *id = qdict_get_try_str(qdict, "id"); - AnnounceParameters *params = QAPI_CLONE(AnnounceParameters, - migrate_announce_params()); - - qapi_free_strList(params->interfaces); - params->interfaces = hmp_split_at_comma(interfaces_str); - params->has_interfaces = params->interfaces != NULL; - params->id = g_strdup(id); - qmp_announce_self(params, NULL); - qapi_free_AnnounceParameters(params); -} - void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) { qmp_migrate_cancel(NULL); @@ -996,39 +968,6 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) } } -void hmp_netdev_add(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - QemuOpts *opts; - const char *type = qdict_get_try_str(qdict, "type"); - - if (type && is_help_option(type)) { - show_netdevs(); - return; - } - opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err); - if (err) { - goto out; - } - - netdev_add(opts, &err); - if (err) { - qemu_opts_del(opts); - } - -out: - hmp_handle_error(mon, err); -} - -void hmp_netdev_del(Monitor *mon, const QDict *qdict) -{ - const char *id = qdict_get_str(qdict, "id"); - Error *err = NULL; - - qmp_netdev_del(id, &err); - hmp_handle_error(mon, err); -} - void hmp_getfd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); diff --git a/monitor/misc.c b/monitor/misc.c index 0cf2518ce1..bf3d863227 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1268,21 +1268,6 @@ int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) return ret; } -void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - int i; - - if (nb_args != 2) { - return; - } - len = strlen(str); - readline_set_completion_index(rs, len); - for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) { - readline_add_completion_of(rs, str, NetClientDriver_str(i)); - } -} - void device_add_completion(ReadLineState *rs, int nb_args, const char *str) { GSList *list, *elt; @@ -1365,47 +1350,6 @@ void device_del_completion(ReadLineState *rs, int nb_args, const char *str) peripheral_device_del_completion(rs, str); } -void set_link_completion(ReadLineState *rs, int nb_args, const char *str) -{ - size_t len; - - len = strlen(str); - readline_set_completion_index(rs, len); - if (nb_args == 2) { - NetClientState *ncs[MAX_QUEUE_NUM]; - int count, i; - count = qemu_find_net_clients_except(NULL, ncs, - NET_CLIENT_DRIVER_NONE, - MAX_QUEUE_NUM); - for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { - readline_add_completion_of(rs, str, ncs[i]->name); - } - } else if (nb_args == 3) { - readline_add_completion_of(rs, str, "on"); - readline_add_completion_of(rs, str, "off"); - } -} - -void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) -{ - int len, count, i; - NetClientState *ncs[MAX_QUEUE_NUM]; - - if (nb_args != 2) { - return; - } - - len = strlen(str); - readline_set_completion_index(rs, len); - count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC, - MAX_QUEUE_NUM); - for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { - if (ncs[i]->is_netdev) { - readline_add_completion_of(rs, str, ncs[i]->name); - } - } -} - void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) { int i; diff --git a/net/meson.build b/net/meson.build index 6cd1e3dab3..87afca3e93 100644 --- a/net/meson.build +++ b/net/meson.build @@ -10,6 +10,7 @@ softmmu_ss.add(files( 'filter-rewriter.c', 'filter.c', 'hub.c', + 'net-hmp-cmds.c', 'net.c', 'queue.c', 'socket.c', diff --git a/net/net-hmp-cmds.c b/net/net-hmp-cmds.c new file mode 100644 index 0000000000..d7427ea4f8 --- /dev/null +++ b/net/net-hmp-cmds.c @@ -0,0 +1,142 @@ +/* + * Human Monitor Interface commands + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "migration/misc.h" +#include "monitor/hmp.h" +#include "net/net.h" +#include "qapi/clone-visitor.h" +#include "qapi/qapi-commands-net.h" +#include "qapi/qapi-visit-net.h" +#include "qapi/qmp/qdict.h" +#include "qemu/config-file.h" +#include "qemu/help_option.h" +#include "qemu/option.h" + +void hmp_set_link(Monitor *mon, const QDict *qdict) +{ + const char *name = qdict_get_str(qdict, "name"); + bool up = qdict_get_bool(qdict, "up"); + Error *err = NULL; + + qmp_set_link(name, up, &err); + hmp_handle_error(mon, err); +} + + +void hmp_announce_self(Monitor *mon, const QDict *qdict) +{ + const char *interfaces_str = qdict_get_try_str(qdict, "interfaces"); + const char *id = qdict_get_try_str(qdict, "id"); + AnnounceParameters *params = QAPI_CLONE(AnnounceParameters, + migrate_announce_params()); + + qapi_free_strList(params->interfaces); + params->interfaces = hmp_split_at_comma(interfaces_str); + params->has_interfaces = params->interfaces != NULL; + params->id = g_strdup(id); + qmp_announce_self(params, NULL); + qapi_free_AnnounceParameters(params); +} + +void hmp_netdev_add(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + QemuOpts *opts; + const char *type = qdict_get_try_str(qdict, "type"); + + if (type && is_help_option(type)) { + show_netdevs(); + return; + } + opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err); + if (err) { + goto out; + } + + netdev_add(opts, &err); + if (err) { + qemu_opts_del(opts); + } + +out: + hmp_handle_error(mon, err); +} + +void hmp_netdev_del(Monitor *mon, const QDict *qdict) +{ + const char *id = qdict_get_str(qdict, "id"); + Error *err = NULL; + + qmp_netdev_del(id, &err); + hmp_handle_error(mon, err); +} + + +void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + int i; + + if (nb_args != 2) { + return; + } + len = strlen(str); + readline_set_completion_index(rs, len); + for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) { + readline_add_completion_of(rs, str, NetClientDriver_str(i)); + } +} + +void set_link_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + NetClientState *ncs[MAX_QUEUE_NUM]; + int count, i; + count = qemu_find_net_clients_except(NULL, ncs, + NET_CLIENT_DRIVER_NONE, + MAX_QUEUE_NUM); + for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { + readline_add_completion_of(rs, str, ncs[i]->name); + } + } else if (nb_args == 3) { + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); + } +} + +void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) +{ + int len, count, i; + NetClientState *ncs[MAX_QUEUE_NUM]; + + if (nb_args != 2) { + return; + } + + len = strlen(str); + readline_set_completion_index(rs, len); + count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC, + MAX_QUEUE_NUM); + for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { + if (ncs[i]->is_netdev) { + readline_add_completion_of(rs, str, ncs[i]->name); + } + } +} From ae71d13d4e606cc89f361ce813e85fb6f6e92096 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:30 +0100 Subject: [PATCH 453/814] net: Move hmp_info_network() to net-hmp-cmds.c Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-17-armbru@redhat.com> --- include/monitor/hmp.h | 1 + include/net/net.h | 4 +++- monitor/hmp-cmds.c | 1 - monitor/misc.c | 1 - net/net-hmp-cmds.c | 28 ++++++++++++++++++++++++++++ net/net.c | 28 +--------------------------- 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index d60d1305b8..a248ee9ed1 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -56,6 +56,7 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_nmi(Monitor *mon, const QDict *qdict); +void hmp_info_network(Monitor *mon, const QDict *qdict); void hmp_set_link(Monitor *mon, const QDict *qdict); void hmp_balloon(Monitor *mon, const QDict *qdict); void hmp_loadvm(Monitor *mon, const QDict *qdict); diff --git a/include/net/net.h b/include/net/net.h index dc20b31e9f..fad589cc1d 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -115,6 +115,8 @@ struct NetClientState { QTAILQ_HEAD(, NetFilterState) filters; }; +typedef QTAILQ_HEAD(NetClientStateList, NetClientState) NetClientStateList; + typedef struct NICState { NetClientState *ncs; NICConf *conf; @@ -196,7 +198,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, const char *default_model); void print_net_client(Monitor *mon, NetClientState *nc); -void hmp_info_network(Monitor *mon, const QDict *qdict); void net_socket_rs_init(SocketReadState *rs, SocketReadStateFinalize *finalize, bool vnet_hdr); @@ -222,6 +223,7 @@ extern NICInfo nd_table[MAX_NICS]; extern const char *host_net_devices[]; /* from net.c */ +extern NetClientStateList net_clients; bool netdev_is_modern(const char *optarg); void netdev_parse_modern(const char *optarg); void net_client_parse(QemuOptsList *opts_list, const char *str); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 90259d02d7..b059af7abd 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "monitor/hmp.h" -#include "net/net.h" #include "sysemu/runstate.h" #include "qemu/sockets.h" #include "qemu/help_option.h" diff --git a/monitor/misc.c b/monitor/misc.c index bf3d863227..77a76b2b5f 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -26,7 +26,6 @@ #include "monitor-internal.h" #include "monitor/qdev.h" #include "exec/gdbstub.h" -#include "net/net.h" #include "net/slirp.h" #include "ui/qemu-spice.h" #include "qemu/ctype.h" diff --git a/net/net-hmp-cmds.c b/net/net-hmp-cmds.c index d7427ea4f8..41d326bf5f 100644 --- a/net/net-hmp-cmds.c +++ b/net/net-hmp-cmds.c @@ -16,7 +16,9 @@ #include "qemu/osdep.h" #include "migration/misc.h" #include "monitor/hmp.h" +#include "monitor/monitor.h" #include "net/net.h" +#include "net/hub.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-commands-net.h" #include "qapi/qapi-visit-net.h" @@ -25,6 +27,32 @@ #include "qemu/help_option.h" #include "qemu/option.h" +void hmp_info_network(Monitor *mon, const QDict *qdict) +{ + NetClientState *nc, *peer; + NetClientDriver type; + + net_hub_info(mon); + + QTAILQ_FOREACH(nc, &net_clients, next) { + peer = nc->peer; + type = nc->info->type; + + /* Skip if already printed in hub info */ + if (net_hub_id_for_client(nc, NULL) == 0) { + continue; + } + + if (!peer || type == NET_CLIENT_DRIVER_NIC) { + print_net_client(mon, nc); + } /* else it's a netdev connected to a NIC, printed with the NIC */ + if (peer && type == NET_CLIENT_DRIVER_NIC) { + monitor_printf(mon, " \\ "); + print_net_client(mon, peer); + } + } +} + void hmp_set_link(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_str(qdict, "name"); diff --git a/net/net.c b/net/net.c index 2d01472998..251fc5ab55 100644 --- a/net/net.c +++ b/net/net.c @@ -63,7 +63,7 @@ #endif static VMChangeStateEntry *net_change_state_entry; -static QTAILQ_HEAD(, NetClientState) net_clients; +NetClientStateList net_clients; typedef struct NetdevQueueEntry { Netdev *nd; @@ -1345,32 +1345,6 @@ RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp) return filter_list; } -void hmp_info_network(Monitor *mon, const QDict *qdict) -{ - NetClientState *nc, *peer; - NetClientDriver type; - - net_hub_info(mon); - - QTAILQ_FOREACH(nc, &net_clients, next) { - peer = nc->peer; - type = nc->info->type; - - /* Skip if already printed in hub info */ - if (net_hub_id_for_client(nc, NULL) == 0) { - continue; - } - - if (!peer || type == NET_CLIENT_DRIVER_NIC) { - print_net_client(mon, nc); - } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_DRIVER_NIC) { - monitor_printf(mon, " \\ "); - print_net_client(mon, peer); - } - } -} - void colo_notify_filters_event(int event, Error **errp) { NetClientState *nc; From 119f50ce30f1dfdfd33e4ec7455b147834c794d5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:31 +0100 Subject: [PATCH 454/814] migration: Move HMP commands from monitor/ to migration/ This moves these commands from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Migration". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-18-armbru@redhat.com> Reviewed-by: Juan Quintela --- migration/meson.build | 1 + migration/migration-hmp-cmds.c | 807 +++++++++++++++++++++++++++++++++ monitor/hmp-cmds.c | 703 ---------------------------- monitor/misc.c | 82 ---- 4 files changed, 808 insertions(+), 785 deletions(-) create mode 100644 migration/migration-hmp-cmds.c diff --git a/migration/meson.build b/migration/meson.build index 690487cf1a..a9e7e18793 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -18,6 +18,7 @@ softmmu_ss.add(files( 'exec.c', 'fd.c', 'global_state.c', + 'migration-hmp-cmds.c', 'migration.c', 'multifd.c', 'multifd-zlib.c', diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c new file mode 100644 index 0000000000..ef25bc8929 --- /dev/null +++ b/migration/migration-hmp-cmds.c @@ -0,0 +1,807 @@ +/* + * HMP commands related to migration + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "block/qapi.h" +#include "migration/misc.h" +#include "migration/snapshot.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-migration.h" +#include "qapi/qapi-visit-migration.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qerror.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" +#include "qemu/sockets.h" +#include "sysemu/runstate.h" +#include "ui/qemu-spice.h" + +void hmp_info_migrate(Monitor *mon, const QDict *qdict) +{ + 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"); + while (reasons) { + monitor_printf(mon, " %s\n", reasons->value); + reasons = reasons->next; + } + } + + if (info->has_status) { + monitor_printf(mon, "Migration status: %s", + MigrationStatus_str(info->status)); + if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) { + monitor_printf(mon, " (%s)\n", info->error_desc); + } else { + 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->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->ram) { + monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", + info->ram->transferred >> 10); + monitor_printf(mon, "throughput: %0.2f mbps\n", + info->ram->mbps); + monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", + info->ram->remaining >> 10); + monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", + info->ram->total >> 10); + monitor_printf(mon, "duplicate: %" PRIu64 " pages\n", + info->ram->duplicate); + monitor_printf(mon, "skipped: %" PRIu64 " pages\n", + info->ram->skipped); + 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", + info->ram->pages_per_second); + + if (info->ram->dirty_pages_rate) { + monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n", + info->ram->dirty_pages_rate); + } + if (info->ram->postcopy_requests) { + monitor_printf(mon, "postcopy request count: %" PRIu64 "\n", + 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); + } + if (info->ram->dirty_sync_missed_zero_copy) { + monitor_printf(mon, + "Zero-copy-send fallbacks happened: %" PRIu64 " times\n", + info->ram->dirty_sync_missed_zero_copy); + } + } + + if (info->disk) { + monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n", + info->disk->transferred >> 10); + monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n", + info->disk->remaining >> 10); + monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n", + info->disk->total >> 10); + } + + 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", + info->xbzrle_cache->overflow); + } + + if (info->compression) { + monitor_printf(mon, "compression pages: %" PRIu64 " pages\n", + info->compression->pages); + monitor_printf(mon, "compression busy: %" PRIu64 "\n", + info->compression->busy); + monitor_printf(mon, "compression busy rate: %0.2f\n", + info->compression->busy_rate); + monitor_printf(mon, "compressed size: %" PRIu64 " kbytes\n", + info->compression->compressed_size >> 10); + monitor_printf(mon, "compression rate: %0.2f\n", + info->compression->compression_rate); + } + + if (info->has_cpu_throttle_percentage) { + monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n", + info->cpu_throttle_percentage); + } + + if (info->has_postcopy_blocktime) { + monitor_printf(mon, "postcopy blocktime: %u\n", + info->postcopy_blocktime); + } + + if (info->has_postcopy_vcpu_blocktime) { + Visitor *v; + char *str; + v = string_output_visitor_new(false, &str); + visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, + &error_abort); + visit_complete(v, &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); + } + + qapi_free_MigrationInfo(info); +} + +void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict) +{ + MigrationCapabilityStatusList *caps, *cap; + + caps = qmp_query_migrate_capabilities(NULL); + + if (caps) { + for (cap = caps; cap; cap = cap->next) { + monitor_printf(mon, "%s: %s\n", + MigrationCapability_str(cap->value->capability), + cap->value->state ? "on" : "off"); + } + } + + qapi_free_MigrationCapabilityStatusList(caps); +} + +void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) +{ + MigrationParameters *params; + + params = qmp_query_migrate_parameters(NULL); + + if (params) { + monitor_printf(mon, "%s: %" PRIu64 " ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL), + params->announce_initial); + monitor_printf(mon, "%s: %" PRIu64 " ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX), + params->announce_max); + monitor_printf(mon, "%s: %" PRIu64 "\n", + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS), + params->announce_rounds); + monitor_printf(mon, "%s: %" PRIu64 " ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP), + params->announce_step); + assert(params->has_compress_level); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL), + params->compress_level); + assert(params->has_compress_threads); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_THREADS), + params->compress_threads); + assert(params->has_compress_wait_thread); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD), + params->compress_wait_thread ? "on" : "off"); + assert(params->has_decompress_threads); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS), + params->decompress_threads); + assert(params->has_throttle_trigger_threshold); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD), + params->throttle_trigger_threshold); + assert(params->has_cpu_throttle_initial); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL), + params->cpu_throttle_initial); + assert(params->has_cpu_throttle_increment); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT), + params->cpu_throttle_increment); + assert(params->has_cpu_throttle_tailslow); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW), + params->cpu_throttle_tailslow ? "on" : "off"); + assert(params->has_max_cpu_throttle); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE), + params->max_cpu_throttle); + assert(params->tls_creds); + monitor_printf(mon, "%s: '%s'\n", + MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS), + params->tls_creds); + assert(params->tls_hostname); + monitor_printf(mon, "%s: '%s'\n", + MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME), + params->tls_hostname); + assert(params->has_max_bandwidth); + monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n", + MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH), + params->max_bandwidth); + assert(params->has_downtime_limit); + monitor_printf(mon, "%s: %" PRIu64 " ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT), + params->downtime_limit); + assert(params->has_x_checkpoint_delay); + monitor_printf(mon, "%s: %u ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY), + params->x_checkpoint_delay); + assert(params->has_block_incremental); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL), + params->block_incremental ? "on" : "off"); + monitor_printf(mon, "%s: %u\n", + MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS), + params->multifd_channels); + monitor_printf(mon, "%s: %s\n", + MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION), + MultiFDCompression_str(params->multifd_compression)); + monitor_printf(mon, "%s: %" PRIu64 " bytes\n", + MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE), + params->xbzrle_cache_size); + monitor_printf(mon, "%s: %" PRIu64 "\n", + MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH), + params->max_postcopy_bandwidth); + monitor_printf(mon, "%s: '%s'\n", + MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ), + params->tls_authz); + + if (params->has_block_bitmap_mapping) { + const BitmapMigrationNodeAliasList *bmnal; + + monitor_printf(mon, "%s:\n", + MigrationParameter_str( + MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING)); + + for (bmnal = params->block_bitmap_mapping; + bmnal; + bmnal = bmnal->next) + { + const BitmapMigrationNodeAlias *bmna = bmnal->value; + const BitmapMigrationBitmapAliasList *bmbal; + + monitor_printf(mon, " '%s' -> '%s'\n", + bmna->node_name, bmna->alias); + + for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) { + const BitmapMigrationBitmapAlias *bmba = bmbal->value; + + monitor_printf(mon, " '%s' -> '%s'\n", + bmba->name, bmba->alias); + } + } + } + } + + qapi_free_MigrationParameters(params); +} + +void hmp_loadvm(Monitor *mon, const QDict *qdict) +{ + int saved_vm_running = runstate_is_running(); + const char *name = qdict_get_str(qdict, "name"); + Error *err = NULL; + + vm_stop(RUN_STATE_RESTORE_VM); + + if (load_snapshot(name, NULL, false, NULL, &err) && saved_vm_running) { + vm_start(); + } + hmp_handle_error(mon, err); +} + +void hmp_savevm(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + save_snapshot(qdict_get_try_str(qdict, "name"), + true, NULL, false, NULL, &err); + hmp_handle_error(mon, err); +} + +void hmp_delvm(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *name = qdict_get_str(qdict, "name"); + + delete_snapshot(name, false, NULL, &err); + hmp_handle_error(mon, err); +} + +void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) +{ + qmp_migrate_cancel(NULL); +} + +void hmp_migrate_continue(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *state = qdict_get_str(qdict, "state"); + int val = qapi_enum_parse(&MigrationStatus_lookup, state, -1, &err); + + if (val >= 0) { + qmp_migrate_continue(val, &err); + } + + hmp_handle_error(mon, err); +} + +void hmp_migrate_incoming(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *uri = qdict_get_str(qdict, "uri"); + + qmp_migrate_incoming(uri, &err); + + hmp_handle_error(mon, err); +} + +void hmp_migrate_recover(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *uri = qdict_get_str(qdict, "uri"); + + qmp_migrate_recover(uri, &err); + + hmp_handle_error(mon, err); +} + +void hmp_migrate_pause(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qmp_migrate_pause(&err); + + hmp_handle_error(mon, err); +} + + +void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) +{ + const char *cap = qdict_get_str(qdict, "capability"); + bool state = qdict_get_bool(qdict, "state"); + Error *err = NULL; + MigrationCapabilityStatusList *caps = NULL; + MigrationCapabilityStatus *value; + int val; + + val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err); + if (val < 0) { + goto end; + } + + value = g_malloc0(sizeof(*value)); + value->capability = val; + value->state = state; + QAPI_LIST_PREPEND(caps, value); + qmp_migrate_set_capabilities(caps, &err); + qapi_free_MigrationCapabilityStatusList(caps); + +end: + hmp_handle_error(mon, err); +} + +void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) +{ + const char *param = qdict_get_str(qdict, "parameter"); + const char *valuestr = qdict_get_str(qdict, "value"); + Visitor *v = string_input_visitor_new(valuestr); + MigrateSetParameters *p = g_new0(MigrateSetParameters, 1); + uint64_t valuebw = 0; + uint64_t cache_size; + Error *err = NULL; + int val, ret; + + val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err); + if (val < 0) { + goto cleanup; + } + + switch (val) { + case MIGRATION_PARAMETER_COMPRESS_LEVEL: + p->has_compress_level = true; + visit_type_uint8(v, param, &p->compress_level, &err); + break; + case MIGRATION_PARAMETER_COMPRESS_THREADS: + p->has_compress_threads = true; + visit_type_uint8(v, param, &p->compress_threads, &err); + break; + case MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD: + p->has_compress_wait_thread = true; + visit_type_bool(v, param, &p->compress_wait_thread, &err); + break; + case MIGRATION_PARAMETER_DECOMPRESS_THREADS: + p->has_decompress_threads = true; + visit_type_uint8(v, param, &p->decompress_threads, &err); + break; + case MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD: + p->has_throttle_trigger_threshold = true; + visit_type_uint8(v, param, &p->throttle_trigger_threshold, &err); + break; + case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL: + p->has_cpu_throttle_initial = true; + visit_type_uint8(v, param, &p->cpu_throttle_initial, &err); + break; + case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT: + p->has_cpu_throttle_increment = true; + visit_type_uint8(v, param, &p->cpu_throttle_increment, &err); + break; + case MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW: + p->has_cpu_throttle_tailslow = true; + visit_type_bool(v, param, &p->cpu_throttle_tailslow, &err); + break; + case MIGRATION_PARAMETER_MAX_CPU_THROTTLE: + p->has_max_cpu_throttle = true; + visit_type_uint8(v, param, &p->max_cpu_throttle, &err); + break; + case MIGRATION_PARAMETER_TLS_CREDS: + p->tls_creds = g_new0(StrOrNull, 1); + p->tls_creds->type = QTYPE_QSTRING; + visit_type_str(v, param, &p->tls_creds->u.s, &err); + break; + case MIGRATION_PARAMETER_TLS_HOSTNAME: + p->tls_hostname = g_new0(StrOrNull, 1); + p->tls_hostname->type = QTYPE_QSTRING; + visit_type_str(v, param, &p->tls_hostname->u.s, &err); + break; + case MIGRATION_PARAMETER_TLS_AUTHZ: + p->tls_authz = g_new0(StrOrNull, 1); + p->tls_authz->type = QTYPE_QSTRING; + visit_type_str(v, param, &p->tls_authz->u.s, &err); + break; + case MIGRATION_PARAMETER_MAX_BANDWIDTH: + p->has_max_bandwidth = true; + /* + * Can't use visit_type_size() here, because it + * defaults to Bytes rather than Mebibytes. + */ + ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw); + if (ret < 0 || valuebw > INT64_MAX + || (size_t)valuebw != valuebw) { + error_setg(&err, "Invalid size %s", valuestr); + break; + } + p->max_bandwidth = valuebw; + break; + case MIGRATION_PARAMETER_DOWNTIME_LIMIT: + p->has_downtime_limit = true; + visit_type_size(v, param, &p->downtime_limit, &err); + break; + case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY: + p->has_x_checkpoint_delay = true; + visit_type_uint32(v, param, &p->x_checkpoint_delay, &err); + break; + case MIGRATION_PARAMETER_BLOCK_INCREMENTAL: + p->has_block_incremental = true; + visit_type_bool(v, param, &p->block_incremental, &err); + break; + case MIGRATION_PARAMETER_MULTIFD_CHANNELS: + p->has_multifd_channels = true; + visit_type_uint8(v, param, &p->multifd_channels, &err); + break; + case MIGRATION_PARAMETER_MULTIFD_COMPRESSION: + p->has_multifd_compression = true; + visit_type_MultiFDCompression(v, param, &p->multifd_compression, + &err); + break; + case MIGRATION_PARAMETER_MULTIFD_ZLIB_LEVEL: + p->has_multifd_zlib_level = true; + visit_type_uint8(v, param, &p->multifd_zlib_level, &err); + break; + case MIGRATION_PARAMETER_MULTIFD_ZSTD_LEVEL: + p->has_multifd_zstd_level = true; + visit_type_uint8(v, param, &p->multifd_zstd_level, &err); + break; + case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: + p->has_xbzrle_cache_size = true; + if (!visit_type_size(v, param, &cache_size, &err)) { + break; + } + if (cache_size > INT64_MAX || (size_t)cache_size != cache_size) { + error_setg(&err, "Invalid size %s", valuestr); + break; + } + p->xbzrle_cache_size = cache_size; + break; + case MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH: + p->has_max_postcopy_bandwidth = true; + visit_type_size(v, param, &p->max_postcopy_bandwidth, &err); + break; + case MIGRATION_PARAMETER_ANNOUNCE_INITIAL: + p->has_announce_initial = true; + visit_type_size(v, param, &p->announce_initial, &err); + break; + case MIGRATION_PARAMETER_ANNOUNCE_MAX: + p->has_announce_max = true; + visit_type_size(v, param, &p->announce_max, &err); + break; + case MIGRATION_PARAMETER_ANNOUNCE_ROUNDS: + p->has_announce_rounds = true; + visit_type_size(v, param, &p->announce_rounds, &err); + break; + case MIGRATION_PARAMETER_ANNOUNCE_STEP: + p->has_announce_step = true; + visit_type_size(v, param, &p->announce_step, &err); + break; + case MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING: + error_setg(&err, "The block-bitmap-mapping parameter can only be set " + "through QMP"); + break; + default: + assert(0); + } + + if (err) { + goto cleanup; + } + + qmp_migrate_set_parameters(p, &err); + + cleanup: + qapi_free_MigrateSetParameters(p); + visit_free(v); + hmp_handle_error(mon, err); +} + +void hmp_client_migrate_info(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *hostname = qdict_get_str(qdict, "hostname"); + bool has_port = qdict_haskey(qdict, "port"); + int port = qdict_get_try_int(qdict, "port", -1); + bool has_tls_port = qdict_haskey(qdict, "tls-port"); + int tls_port = qdict_get_try_int(qdict, "tls-port", -1); + const char *cert_subject = qdict_get_try_str(qdict, "cert-subject"); + + qmp_client_migrate_info(protocol, hostname, + has_port, port, has_tls_port, tls_port, + cert_subject, &err); + hmp_handle_error(mon, err); +} + +void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + qmp_migrate_start_postcopy(&err); + hmp_handle_error(mon, err); +} + +void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qmp_x_colo_lost_heartbeat(&err); + hmp_handle_error(mon, err); +} + +typedef struct HMPMigrationStatus { + QEMUTimer *timer; + Monitor *mon; + bool is_block_migration; +} HMPMigrationStatus; + +static void hmp_migrate_status_cb(void *opaque) +{ + HMPMigrationStatus *status = opaque; + MigrationInfo *info; + + info = qmp_query_migrate(NULL); + if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE || + info->status == MIGRATION_STATUS_SETUP) { + if (info->disk) { + int progress; + + if (info->disk->remaining) { + progress = info->disk->transferred * 100 / info->disk->total; + } else { + progress = 100; + } + + monitor_printf(status->mon, "Completed %d %%\r", progress); + monitor_flush(status->mon); + } + + timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); + } else { + if (status->is_block_migration) { + monitor_printf(status->mon, "\n"); + } + if (info->error_desc) { + error_report("%s", info->error_desc); + } + monitor_resume(status->mon); + timer_free(status->timer); + g_free(status); + } + + qapi_free_MigrationInfo(info); +} + +void hmp_migrate(Monitor *mon, const QDict *qdict) +{ + bool detach = qdict_get_try_bool(qdict, "detach", false); + bool blk = qdict_get_try_bool(qdict, "blk", false); + bool inc = qdict_get_try_bool(qdict, "inc", false); + bool resume = qdict_get_try_bool(qdict, "resume", false); + const char *uri = qdict_get_str(qdict, "uri"); + Error *err = NULL; + + qmp_migrate(uri, !!blk, blk, !!inc, inc, + false, false, true, resume, &err); + if (hmp_handle_error(mon, err)) { + return; + } + + if (!detach) { + HMPMigrationStatus *status; + + if (monitor_suspend(mon) < 0) { + monitor_printf(mon, "terminal does not allow synchronous " + "migration, continuing detached\n"); + return; + } + + status = g_malloc0(sizeof(*status)); + status->mon = mon; + status->is_block_migration = blk || inc; + status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb, + status); + timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); + } +} + +void migrate_set_capability_completion(ReadLineState *rs, int nb_args, + const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + int i; + for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { + readline_add_completion_of(rs, str, MigrationCapability_str(i)); + } + } else if (nb_args == 3) { + readline_add_completion_of(rs, str, "on"); + readline_add_completion_of(rs, str, "off"); + } +} + +void migrate_set_parameter_completion(ReadLineState *rs, int nb_args, + const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + int i; + for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { + readline_add_completion_of(rs, str, MigrationParameter_str(i)); + } + } +} + +static void vm_completion(ReadLineState *rs, const char *str) +{ + size_t len; + BlockDriverState *bs; + BdrvNextIterator it; + + len = strlen(str); + readline_set_completion_index(rs, len); + + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { + SnapshotInfoList *snapshots, *snapshot; + AioContext *ctx = bdrv_get_aio_context(bs); + bool ok = false; + + aio_context_acquire(ctx); + if (bdrv_can_snapshot(bs)) { + ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0; + } + aio_context_release(ctx); + if (!ok) { + continue; + } + + snapshot = snapshots; + while (snapshot) { + readline_add_completion_of(rs, str, snapshot->value->name); + readline_add_completion_of(rs, str, snapshot->value->id); + snapshot = snapshot->next; + } + qapi_free_SnapshotInfoList(snapshots); + } + +} + +void delvm_completion(ReadLineState *rs, int nb_args, const char *str) +{ + if (nb_args == 2) { + vm_completion(rs, str); + } +} + +void loadvm_completion(ReadLineState *rs, int nb_args, const char *str) +{ + if (nb_args == 2) { + vm_completion(rs, str); + } +} diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index b059af7abd..4da6b7cccc 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -15,30 +15,20 @@ #include "qemu/osdep.h" #include "monitor/hmp.h" -#include "sysemu/runstate.h" -#include "qemu/sockets.h" #include "qemu/help_option.h" #include "monitor/monitor.h" #include "qapi/error.h" -#include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-commands-control.h" -#include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" #include "qapi/qapi-commands-virtio.h" -#include "qapi/qapi-visit-migration.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qapi/string-input-visitor.h" -#include "qapi/string-output-visitor.h" #include "qemu/cutils.h" -#include "qemu/error-report.h" #include "hw/core/cpu.h" #include "hw/intc/intc.h" -#include "migration/snapshot.h" -#include "migration/misc.h" bool hmp_handle_error(Monitor *mon, Error *err) { @@ -111,324 +101,6 @@ void hmp_info_status(Monitor *mon, const QDict *qdict) qapi_free_StatusInfo(info); } -void hmp_info_migrate(Monitor *mon, const QDict *qdict) -{ - 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"); - while (reasons) { - monitor_printf(mon, " %s\n", reasons->value); - reasons = reasons->next; - } - } - - if (info->has_status) { - monitor_printf(mon, "Migration status: %s", - MigrationStatus_str(info->status)); - if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) { - monitor_printf(mon, " (%s)\n", info->error_desc); - } else { - 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->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->ram) { - monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", - info->ram->transferred >> 10); - monitor_printf(mon, "throughput: %0.2f mbps\n", - info->ram->mbps); - monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", - info->ram->remaining >> 10); - monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", - info->ram->total >> 10); - monitor_printf(mon, "duplicate: %" PRIu64 " pages\n", - info->ram->duplicate); - monitor_printf(mon, "skipped: %" PRIu64 " pages\n", - info->ram->skipped); - 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", - info->ram->pages_per_second); - - if (info->ram->dirty_pages_rate) { - monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n", - info->ram->dirty_pages_rate); - } - if (info->ram->postcopy_requests) { - monitor_printf(mon, "postcopy request count: %" PRIu64 "\n", - 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); - } - if (info->ram->dirty_sync_missed_zero_copy) { - monitor_printf(mon, - "Zero-copy-send fallbacks happened: %" PRIu64 " times\n", - info->ram->dirty_sync_missed_zero_copy); - } - } - - if (info->disk) { - monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n", - info->disk->transferred >> 10); - monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n", - info->disk->remaining >> 10); - monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n", - info->disk->total >> 10); - } - - 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", - info->xbzrle_cache->overflow); - } - - if (info->compression) { - monitor_printf(mon, "compression pages: %" PRIu64 " pages\n", - info->compression->pages); - monitor_printf(mon, "compression busy: %" PRIu64 "\n", - info->compression->busy); - monitor_printf(mon, "compression busy rate: %0.2f\n", - info->compression->busy_rate); - monitor_printf(mon, "compressed size: %" PRIu64 " kbytes\n", - info->compression->compressed_size >> 10); - monitor_printf(mon, "compression rate: %0.2f\n", - info->compression->compression_rate); - } - - if (info->has_cpu_throttle_percentage) { - monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n", - info->cpu_throttle_percentage); - } - - if (info->has_postcopy_blocktime) { - monitor_printf(mon, "postcopy blocktime: %u\n", - info->postcopy_blocktime); - } - - if (info->has_postcopy_vcpu_blocktime) { - Visitor *v; - char *str; - v = string_output_visitor_new(false, &str); - visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, - &error_abort); - visit_complete(v, &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); - } - - qapi_free_MigrationInfo(info); -} - -void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict) -{ - MigrationCapabilityStatusList *caps, *cap; - - caps = qmp_query_migrate_capabilities(NULL); - - if (caps) { - for (cap = caps; cap; cap = cap->next) { - monitor_printf(mon, "%s: %s\n", - MigrationCapability_str(cap->value->capability), - cap->value->state ? "on" : "off"); - } - } - - qapi_free_MigrationCapabilityStatusList(caps); -} - -void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) -{ - MigrationParameters *params; - - params = qmp_query_migrate_parameters(NULL); - - if (params) { - monitor_printf(mon, "%s: %" PRIu64 " ms\n", - MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL), - params->announce_initial); - monitor_printf(mon, "%s: %" PRIu64 " ms\n", - MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX), - params->announce_max); - monitor_printf(mon, "%s: %" PRIu64 "\n", - MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS), - params->announce_rounds); - monitor_printf(mon, "%s: %" PRIu64 " ms\n", - MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP), - params->announce_step); - assert(params->has_compress_level); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL), - params->compress_level); - assert(params->has_compress_threads); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_THREADS), - params->compress_threads); - assert(params->has_compress_wait_thread); - monitor_printf(mon, "%s: %s\n", - MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD), - params->compress_wait_thread ? "on" : "off"); - assert(params->has_decompress_threads); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS), - params->decompress_threads); - assert(params->has_throttle_trigger_threshold); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD), - params->throttle_trigger_threshold); - assert(params->has_cpu_throttle_initial); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL), - params->cpu_throttle_initial); - assert(params->has_cpu_throttle_increment); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT), - params->cpu_throttle_increment); - assert(params->has_cpu_throttle_tailslow); - monitor_printf(mon, "%s: %s\n", - MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW), - params->cpu_throttle_tailslow ? "on" : "off"); - assert(params->has_max_cpu_throttle); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE), - params->max_cpu_throttle); - assert(params->tls_creds); - monitor_printf(mon, "%s: '%s'\n", - MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS), - params->tls_creds); - assert(params->tls_hostname); - monitor_printf(mon, "%s: '%s'\n", - MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME), - params->tls_hostname); - assert(params->has_max_bandwidth); - monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n", - MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH), - params->max_bandwidth); - assert(params->has_downtime_limit); - monitor_printf(mon, "%s: %" PRIu64 " ms\n", - MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT), - params->downtime_limit); - assert(params->has_x_checkpoint_delay); - monitor_printf(mon, "%s: %u ms\n", - MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY), - params->x_checkpoint_delay); - assert(params->has_block_incremental); - monitor_printf(mon, "%s: %s\n", - MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL), - params->block_incremental ? "on" : "off"); - monitor_printf(mon, "%s: %u\n", - MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS), - params->multifd_channels); - monitor_printf(mon, "%s: %s\n", - MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION), - MultiFDCompression_str(params->multifd_compression)); - monitor_printf(mon, "%s: %" PRIu64 " bytes\n", - MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE), - params->xbzrle_cache_size); - monitor_printf(mon, "%s: %" PRIu64 "\n", - MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH), - params->max_postcopy_bandwidth); - monitor_printf(mon, "%s: '%s'\n", - MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ), - params->tls_authz); - - if (params->has_block_bitmap_mapping) { - const BitmapMigrationNodeAliasList *bmnal; - - monitor_printf(mon, "%s:\n", - MigrationParameter_str( - MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING)); - - for (bmnal = params->block_bitmap_mapping; - bmnal; - bmnal = bmnal->next) - { - const BitmapMigrationNodeAlias *bmna = bmnal->value; - const BitmapMigrationBitmapAliasList *bmbal; - - monitor_printf(mon, " '%s' -> '%s'\n", - bmna->node_name, bmna->alias); - - for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) { - const BitmapMigrationBitmapAlias *bmba = bmbal->value; - - monitor_printf(mon, " '%s' -> '%s'\n", - bmba->name, bmba->alias); - } - } - } - } - - qapi_free_MigrationParameters(params); -} - static int hmp_info_pic_foreach(Object *obj, void *opaque) { InterruptStatsProvider *intc; @@ -571,305 +243,6 @@ void hmp_cont(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -void hmp_loadvm(Monitor *mon, const QDict *qdict) -{ - int saved_vm_running = runstate_is_running(); - const char *name = qdict_get_str(qdict, "name"); - Error *err = NULL; - - vm_stop(RUN_STATE_RESTORE_VM); - - if (load_snapshot(name, NULL, false, NULL, &err) && saved_vm_running) { - vm_start(); - } - hmp_handle_error(mon, err); -} - -void hmp_savevm(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - save_snapshot(qdict_get_try_str(qdict, "name"), - true, NULL, false, NULL, &err); - hmp_handle_error(mon, err); -} - -void hmp_delvm(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *name = qdict_get_str(qdict, "name"); - - delete_snapshot(name, false, NULL, &err); - hmp_handle_error(mon, err); -} - -void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) -{ - qmp_migrate_cancel(NULL); -} - -void hmp_migrate_continue(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *state = qdict_get_str(qdict, "state"); - int val = qapi_enum_parse(&MigrationStatus_lookup, state, -1, &err); - - if (val >= 0) { - qmp_migrate_continue(val, &err); - } - - hmp_handle_error(mon, err); -} - -void hmp_migrate_incoming(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *uri = qdict_get_str(qdict, "uri"); - - qmp_migrate_incoming(uri, &err); - - hmp_handle_error(mon, err); -} - -void hmp_migrate_recover(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *uri = qdict_get_str(qdict, "uri"); - - qmp_migrate_recover(uri, &err); - - hmp_handle_error(mon, err); -} - -void hmp_migrate_pause(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - qmp_migrate_pause(&err); - - hmp_handle_error(mon, err); -} - - -void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) -{ - const char *cap = qdict_get_str(qdict, "capability"); - bool state = qdict_get_bool(qdict, "state"); - Error *err = NULL; - MigrationCapabilityStatusList *caps = NULL; - MigrationCapabilityStatus *value; - int val; - - val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err); - if (val < 0) { - goto end; - } - - value = g_malloc0(sizeof(*value)); - value->capability = val; - value->state = state; - QAPI_LIST_PREPEND(caps, value); - qmp_migrate_set_capabilities(caps, &err); - qapi_free_MigrationCapabilityStatusList(caps); - -end: - hmp_handle_error(mon, err); -} - -void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) -{ - const char *param = qdict_get_str(qdict, "parameter"); - const char *valuestr = qdict_get_str(qdict, "value"); - Visitor *v = string_input_visitor_new(valuestr); - MigrateSetParameters *p = g_new0(MigrateSetParameters, 1); - uint64_t valuebw = 0; - uint64_t cache_size; - Error *err = NULL; - int val, ret; - - val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err); - if (val < 0) { - goto cleanup; - } - - switch (val) { - case MIGRATION_PARAMETER_COMPRESS_LEVEL: - p->has_compress_level = true; - visit_type_uint8(v, param, &p->compress_level, &err); - break; - case MIGRATION_PARAMETER_COMPRESS_THREADS: - p->has_compress_threads = true; - visit_type_uint8(v, param, &p->compress_threads, &err); - break; - case MIGRATION_PARAMETER_COMPRESS_WAIT_THREAD: - p->has_compress_wait_thread = true; - visit_type_bool(v, param, &p->compress_wait_thread, &err); - break; - case MIGRATION_PARAMETER_DECOMPRESS_THREADS: - p->has_decompress_threads = true; - visit_type_uint8(v, param, &p->decompress_threads, &err); - break; - case MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD: - p->has_throttle_trigger_threshold = true; - visit_type_uint8(v, param, &p->throttle_trigger_threshold, &err); - break; - case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL: - p->has_cpu_throttle_initial = true; - visit_type_uint8(v, param, &p->cpu_throttle_initial, &err); - break; - case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT: - p->has_cpu_throttle_increment = true; - visit_type_uint8(v, param, &p->cpu_throttle_increment, &err); - break; - case MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW: - p->has_cpu_throttle_tailslow = true; - visit_type_bool(v, param, &p->cpu_throttle_tailslow, &err); - break; - case MIGRATION_PARAMETER_MAX_CPU_THROTTLE: - p->has_max_cpu_throttle = true; - visit_type_uint8(v, param, &p->max_cpu_throttle, &err); - break; - case MIGRATION_PARAMETER_TLS_CREDS: - p->tls_creds = g_new0(StrOrNull, 1); - p->tls_creds->type = QTYPE_QSTRING; - visit_type_str(v, param, &p->tls_creds->u.s, &err); - break; - case MIGRATION_PARAMETER_TLS_HOSTNAME: - p->tls_hostname = g_new0(StrOrNull, 1); - p->tls_hostname->type = QTYPE_QSTRING; - visit_type_str(v, param, &p->tls_hostname->u.s, &err); - break; - case MIGRATION_PARAMETER_TLS_AUTHZ: - p->tls_authz = g_new0(StrOrNull, 1); - p->tls_authz->type = QTYPE_QSTRING; - visit_type_str(v, param, &p->tls_authz->u.s, &err); - break; - case MIGRATION_PARAMETER_MAX_BANDWIDTH: - p->has_max_bandwidth = true; - /* - * Can't use visit_type_size() here, because it - * defaults to Bytes rather than Mebibytes. - */ - ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw); - if (ret < 0 || valuebw > INT64_MAX - || (size_t)valuebw != valuebw) { - error_setg(&err, "Invalid size %s", valuestr); - break; - } - p->max_bandwidth = valuebw; - break; - case MIGRATION_PARAMETER_DOWNTIME_LIMIT: - p->has_downtime_limit = true; - visit_type_size(v, param, &p->downtime_limit, &err); - break; - case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY: - p->has_x_checkpoint_delay = true; - visit_type_uint32(v, param, &p->x_checkpoint_delay, &err); - break; - case MIGRATION_PARAMETER_BLOCK_INCREMENTAL: - p->has_block_incremental = true; - visit_type_bool(v, param, &p->block_incremental, &err); - break; - case MIGRATION_PARAMETER_MULTIFD_CHANNELS: - p->has_multifd_channels = true; - visit_type_uint8(v, param, &p->multifd_channels, &err); - break; - case MIGRATION_PARAMETER_MULTIFD_COMPRESSION: - p->has_multifd_compression = true; - visit_type_MultiFDCompression(v, param, &p->multifd_compression, - &err); - break; - case MIGRATION_PARAMETER_MULTIFD_ZLIB_LEVEL: - p->has_multifd_zlib_level = true; - visit_type_uint8(v, param, &p->multifd_zlib_level, &err); - break; - case MIGRATION_PARAMETER_MULTIFD_ZSTD_LEVEL: - p->has_multifd_zstd_level = true; - visit_type_uint8(v, param, &p->multifd_zstd_level, &err); - break; - case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE: - p->has_xbzrle_cache_size = true; - if (!visit_type_size(v, param, &cache_size, &err)) { - break; - } - if (cache_size > INT64_MAX || (size_t)cache_size != cache_size) { - error_setg(&err, "Invalid size %s", valuestr); - break; - } - p->xbzrle_cache_size = cache_size; - break; - case MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH: - p->has_max_postcopy_bandwidth = true; - visit_type_size(v, param, &p->max_postcopy_bandwidth, &err); - break; - case MIGRATION_PARAMETER_ANNOUNCE_INITIAL: - p->has_announce_initial = true; - visit_type_size(v, param, &p->announce_initial, &err); - break; - case MIGRATION_PARAMETER_ANNOUNCE_MAX: - p->has_announce_max = true; - visit_type_size(v, param, &p->announce_max, &err); - break; - case MIGRATION_PARAMETER_ANNOUNCE_ROUNDS: - p->has_announce_rounds = true; - visit_type_size(v, param, &p->announce_rounds, &err); - break; - case MIGRATION_PARAMETER_ANNOUNCE_STEP: - p->has_announce_step = true; - visit_type_size(v, param, &p->announce_step, &err); - break; - case MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING: - error_setg(&err, "The block-bitmap-mapping parameter can only be set " - "through QMP"); - break; - default: - assert(0); - } - - if (err) { - goto cleanup; - } - - qmp_migrate_set_parameters(p, &err); - - cleanup: - qapi_free_MigrateSetParameters(p); - visit_free(v); - hmp_handle_error(mon, err); -} - -void hmp_client_migrate_info(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *protocol = qdict_get_str(qdict, "protocol"); - const char *hostname = qdict_get_str(qdict, "hostname"); - bool has_port = qdict_haskey(qdict, "port"); - int port = qdict_get_try_int(qdict, "port", -1); - bool has_tls_port = qdict_haskey(qdict, "tls-port"); - int tls_port = qdict_get_try_int(qdict, "tls-port", -1); - const char *cert_subject = qdict_get_try_str(qdict, "cert-subject"); - - qmp_client_migrate_info(protocol, hostname, - has_port, port, has_tls_port, tls_port, - cert_subject, &err); - hmp_handle_error(mon, err); -} - -void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - qmp_migrate_start_postcopy(&err); - hmp_handle_error(mon, err); -} - -void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - qmp_x_colo_lost_heartbeat(&err); - hmp_handle_error(mon, err); -} - void hmp_change(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -891,82 +264,6 @@ void hmp_change(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } -typedef struct HMPMigrationStatus { - QEMUTimer *timer; - Monitor *mon; - bool is_block_migration; -} HMPMigrationStatus; - -static void hmp_migrate_status_cb(void *opaque) -{ - HMPMigrationStatus *status = opaque; - MigrationInfo *info; - - info = qmp_query_migrate(NULL); - if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE || - info->status == MIGRATION_STATUS_SETUP) { - if (info->disk) { - int progress; - - if (info->disk->remaining) { - progress = info->disk->transferred * 100 / info->disk->total; - } else { - progress = 100; - } - - monitor_printf(status->mon, "Completed %d %%\r", progress); - monitor_flush(status->mon); - } - - timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); - } else { - if (status->is_block_migration) { - monitor_printf(status->mon, "\n"); - } - if (info->error_desc) { - error_report("%s", info->error_desc); - } - monitor_resume(status->mon); - timer_free(status->timer); - g_free(status); - } - - qapi_free_MigrationInfo(info); -} - -void hmp_migrate(Monitor *mon, const QDict *qdict) -{ - bool detach = qdict_get_try_bool(qdict, "detach", false); - bool blk = qdict_get_try_bool(qdict, "blk", false); - bool inc = qdict_get_try_bool(qdict, "inc", false); - bool resume = qdict_get_try_bool(qdict, "resume", false); - const char *uri = qdict_get_str(qdict, "uri"); - Error *err = NULL; - - qmp_migrate(uri, !!blk, blk, !!inc, inc, - false, false, true, resume, &err); - if (hmp_handle_error(mon, err)) { - return; - } - - if (!detach) { - HMPMigrationStatus *status; - - if (monitor_suspend(mon) < 0) { - monitor_printf(mon, "terminal does not allow synchronous " - "migration, continuing detached\n"); - return; - } - - status = g_malloc0(sizeof(*status)); - status->mon = mon; - status->is_block_migration = blk || inc; - status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb, - status); - timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)); - } -} - void hmp_getfd(Monitor *mon, const QDict *qdict) { const char *fdname = qdict_get_str(qdict, "fdname"); diff --git a/monitor/misc.c b/monitor/misc.c index 77a76b2b5f..780f2a6b04 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -41,7 +41,6 @@ #include "monitor/hmp.h" #include "exec/address-spaces.h" #include "exec/ioport.h" -#include "block/qapi.h" #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-migration.h" @@ -1362,87 +1361,6 @@ void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) } } -void migrate_set_capability_completion(ReadLineState *rs, int nb_args, - const char *str) -{ - size_t len; - - len = strlen(str); - readline_set_completion_index(rs, len); - if (nb_args == 2) { - int i; - for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { - readline_add_completion_of(rs, str, MigrationCapability_str(i)); - } - } else if (nb_args == 3) { - readline_add_completion_of(rs, str, "on"); - readline_add_completion_of(rs, str, "off"); - } -} - -void migrate_set_parameter_completion(ReadLineState *rs, int nb_args, - const char *str) -{ - size_t len; - - len = strlen(str); - readline_set_completion_index(rs, len); - if (nb_args == 2) { - int i; - for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { - readline_add_completion_of(rs, str, MigrationParameter_str(i)); - } - } -} - -static void vm_completion(ReadLineState *rs, const char *str) -{ - size_t len; - BlockDriverState *bs; - BdrvNextIterator it; - - len = strlen(str); - readline_set_completion_index(rs, len); - - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { - SnapshotInfoList *snapshots, *snapshot; - AioContext *ctx = bdrv_get_aio_context(bs); - bool ok = false; - - aio_context_acquire(ctx); - if (bdrv_can_snapshot(bs)) { - ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0; - } - aio_context_release(ctx); - if (!ok) { - continue; - } - - snapshot = snapshots; - while (snapshot) { - readline_add_completion_of(rs, str, snapshot->value->name); - readline_add_completion_of(rs, str, snapshot->value->id); - snapshot = snapshot->next; - } - qapi_free_SnapshotInfoList(snapshots); - } - -} - -void delvm_completion(ReadLineState *rs, int nb_args, const char *str) -{ - if (nb_args == 2) { - vm_completion(rs, str); - } -} - -void loadvm_completion(ReadLineState *rs, int nb_args, const char *str) -{ - if (nb_args == 2) { - vm_completion(rs, str); - } -} - static int compare_mon_cmd(const void *a, const void *b) { From 27be86351ec94509925e6312f5e79743d698e902 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:32 +0100 Subject: [PATCH 455/814] migration: Move the QMP command from monitor/ to migration/ This moves the command from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to "Migration". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-19-armbru@redhat.com> Reviewed-by: Juan Quintela --- migration/migration.c | 30 ++++++++++++++++++++++++++++++ monitor/misc.c | 31 ------------------------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 52b5d39244..56859d5869 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -61,6 +61,7 @@ #include "sysemu/cpus.h" #include "yank_functions.h" #include "sysemu/qtest.h" +#include "ui/qemu-spice.h" #define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */ @@ -963,6 +964,35 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) return params; } +void qmp_client_migrate_info(const char *protocol, const char *hostname, + bool has_port, int64_t port, + bool has_tls_port, int64_t tls_port, + const char *cert_subject, + Error **errp) +{ + if (strcmp(protocol, "spice") == 0) { + if (!qemu_using_spice(errp)) { + return; + } + + if (!has_port && !has_tls_port) { + error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port"); + return; + } + + if (qemu_spice.migrate_info(hostname, + has_port ? port : -1, + has_tls_port ? tls_port : -1, + cert_subject)) { + error_setg(errp, "Could not set up display for migration"); + return; + } + return; + } + + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "'spice'"); +} + AnnounceParameters *migrate_announce_params(void) { static AnnounceParameters ap; diff --git a/monitor/misc.c b/monitor/misc.c index 780f2a6b04..ff3002a880 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -27,7 +27,6 @@ #include "monitor/qdev.h" #include "exec/gdbstub.h" #include "net/slirp.h" -#include "ui/qemu-spice.h" #include "qemu/ctype.h" #include "disas/disas.h" #include "qemu/log.h" @@ -43,7 +42,6 @@ #include "exec/ioport.h" #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-control.h" -#include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-machine.h" @@ -291,35 +289,6 @@ static void hmp_info_history(Monitor *mon, const QDict *qdict) } } -void qmp_client_migrate_info(const char *protocol, const char *hostname, - bool has_port, int64_t port, - bool has_tls_port, int64_t tls_port, - const char *cert_subject, - Error **errp) -{ - if (strcmp(protocol, "spice") == 0) { - if (!qemu_using_spice(errp)) { - return; - } - - if (!has_port && !has_tls_port) { - error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port"); - return; - } - - if (qemu_spice.migrate_info(hostname, - has_port ? port : -1, - has_tls_port ? tls_port : -1, - cert_subject)) { - error_setg(errp, "Could not set up display for migration"); - return; - } - return; - } - - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "'spice'"); -} - static void hmp_logfile(Monitor *mon, const QDict *qdict) { Error *err = NULL; From fa1cea9d0fafe04d34134b2a90b4e00c6f0a5a2c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:33 +0100 Subject: [PATCH 456/814] virtio: Move HMP commands from monitor/ to hw/virtio/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "virtio". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-20-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/virtio/meson.build | 1 + hw/virtio/virtio-hmp-cmds.c | 321 ++++++++++++++++++++++++++++++++++++ monitor/hmp-cmds.c | 309 ---------------------------------- 3 files changed, 322 insertions(+), 309 deletions(-) create mode 100644 hw/virtio/virtio-hmp-cmds.c diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index f93be2e137..bdec78bfc6 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -67,5 +67,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('virtio-stub.c')) +softmmu_ss.add(files('virtio-hmp-cmds.c')) specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: specific_virtio_ss) diff --git a/hw/virtio/virtio-hmp-cmds.c b/hw/virtio/virtio-hmp-cmds.c new file mode 100644 index 0000000000..477c97dea2 --- /dev/null +++ b/hw/virtio/virtio-hmp-cmds.c @@ -0,0 +1,321 @@ +/* + * HMP commands related to virtio + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/qapi-commands-virtio.h" +#include "qapi/qmp/qdict.h" + + +static void hmp_virtio_dump_protocols(Monitor *mon, + VhostDeviceProtocols *pcol) +{ + strList *pcol_list = pcol->protocols; + while (pcol_list) { + monitor_printf(mon, "\t%s", pcol_list->value); + pcol_list = pcol_list->next; + if (pcol_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + if (pcol->has_unknown_protocols) { + monitor_printf(mon, " unknown-protocols(0x%016"PRIx64")\n", + pcol->unknown_protocols); + } +} + +static void hmp_virtio_dump_status(Monitor *mon, + VirtioDeviceStatus *status) +{ + strList *status_list = status->statuses; + while (status_list) { + monitor_printf(mon, "\t%s", status_list->value); + status_list = status_list->next; + if (status_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + if (status->has_unknown_statuses) { + monitor_printf(mon, " unknown-statuses(0x%016"PRIx32")\n", + status->unknown_statuses); + } +} + +static void hmp_virtio_dump_features(Monitor *mon, + VirtioDeviceFeatures *features) +{ + strList *transport_list = features->transports; + while (transport_list) { + monitor_printf(mon, "\t%s", transport_list->value); + transport_list = transport_list->next; + if (transport_list != NULL) { + monitor_printf(mon, ",\n"); + } + } + + monitor_printf(mon, "\n"); + strList *list = features->dev_features; + if (list) { + while (list) { + monitor_printf(mon, "\t%s", list->value); + list = list->next; + if (list != NULL) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + } + + if (features->has_unknown_dev_features) { + monitor_printf(mon, " unknown-features(0x%016"PRIx64")\n", + features->unknown_dev_features); + } +} + +void hmp_virtio_query(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + VirtioInfoList *list = qmp_x_query_virtio(&err); + VirtioInfoList *node; + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + if (list == NULL) { + monitor_printf(mon, "No VirtIO devices\n"); + return; + } + + node = list; + while (node) { + monitor_printf(mon, "%s [%s]\n", node->value->path, + node->value->name); + node = node->next; + } + qapi_free_VirtioInfoList(list); +} + +void hmp_virtio_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + VirtioStatus *s = qmp_x_query_virtio_status(path, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s %s\n", + s->name, s->vhost_dev ? "(vhost)" : ""); + monitor_printf(mon, " device_id: %d\n", s->device_id); + monitor_printf(mon, " vhost_started: %s\n", + s->vhost_started ? "true" : "false"); + monitor_printf(mon, " bus_name: %s\n", s->bus_name); + monitor_printf(mon, " broken: %s\n", + s->broken ? "true" : "false"); + monitor_printf(mon, " disabled: %s\n", + s->disabled ? "true" : "false"); + monitor_printf(mon, " disable_legacy_check: %s\n", + s->disable_legacy_check ? "true" : "false"); + monitor_printf(mon, " started: %s\n", + s->started ? "true" : "false"); + monitor_printf(mon, " use_started: %s\n", + s->use_started ? "true" : "false"); + monitor_printf(mon, " start_on_kick: %s\n", + s->start_on_kick ? "true" : "false"); + monitor_printf(mon, " use_guest_notifier_mask: %s\n", + s->use_guest_notifier_mask ? "true" : "false"); + monitor_printf(mon, " vm_running: %s\n", + s->vm_running ? "true" : "false"); + monitor_printf(mon, " num_vqs: %"PRId64"\n", s->num_vqs); + monitor_printf(mon, " queue_sel: %d\n", + s->queue_sel); + monitor_printf(mon, " isr: %d\n", s->isr); + monitor_printf(mon, " endianness: %s\n", + s->device_endian); + monitor_printf(mon, " status:\n"); + hmp_virtio_dump_status(mon, s->status); + monitor_printf(mon, " Guest features:\n"); + hmp_virtio_dump_features(mon, s->guest_features); + monitor_printf(mon, " Host features:\n"); + hmp_virtio_dump_features(mon, s->host_features); + monitor_printf(mon, " Backend features:\n"); + hmp_virtio_dump_features(mon, s->backend_features); + + if (s->vhost_dev) { + monitor_printf(mon, " VHost:\n"); + monitor_printf(mon, " nvqs: %d\n", + s->vhost_dev->nvqs); + monitor_printf(mon, " vq_index: %"PRId64"\n", + s->vhost_dev->vq_index); + monitor_printf(mon, " max_queues: %"PRId64"\n", + s->vhost_dev->max_queues); + monitor_printf(mon, " n_mem_sections: %"PRId64"\n", + s->vhost_dev->n_mem_sections); + monitor_printf(mon, " n_tmp_sections: %"PRId64"\n", + s->vhost_dev->n_tmp_sections); + monitor_printf(mon, " backend_cap: %"PRId64"\n", + s->vhost_dev->backend_cap); + monitor_printf(mon, " log_enabled: %s\n", + s->vhost_dev->log_enabled ? "true" : "false"); + monitor_printf(mon, " log_size: %"PRId64"\n", + s->vhost_dev->log_size); + monitor_printf(mon, " Features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->features); + monitor_printf(mon, " Acked features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->acked_features); + monitor_printf(mon, " Backend features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->backend_features); + monitor_printf(mon, " Protocol features:\n"); + hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features); + } + + qapi_free_VirtioStatus(s); +} + +void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + VirtVhostQueueStatus *s = + qmp_x_query_virtio_vhost_queue_status(path, queue, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s (vhost)\n", + s->name); + monitor_printf(mon, " kick: %"PRId64"\n", s->kick); + monitor_printf(mon, " call: %"PRId64"\n", s->call); + monitor_printf(mon, " VRing:\n"); + monitor_printf(mon, " num: %"PRId64"\n", s->num); + monitor_printf(mon, " desc: 0x%016"PRIx64"\n", s->desc); + monitor_printf(mon, " desc_phys: 0x%016"PRIx64"\n", + s->desc_phys); + monitor_printf(mon, " desc_size: %"PRId32"\n", s->desc_size); + monitor_printf(mon, " avail: 0x%016"PRIx64"\n", s->avail); + monitor_printf(mon, " avail_phys: 0x%016"PRIx64"\n", + s->avail_phys); + monitor_printf(mon, " avail_size: %"PRId32"\n", s->avail_size); + monitor_printf(mon, " used: 0x%016"PRIx64"\n", s->used); + monitor_printf(mon, " used_phys: 0x%016"PRIx64"\n", + s->used_phys); + monitor_printf(mon, " used_size: %"PRId32"\n", s->used_size); + + qapi_free_VirtVhostQueueStatus(s); +} + +void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s\n", s->name); + monitor_printf(mon, " queue_index: %d\n", s->queue_index); + monitor_printf(mon, " inuse: %d\n", s->inuse); + monitor_printf(mon, " used_idx: %d\n", s->used_idx); + monitor_printf(mon, " signalled_used: %d\n", + s->signalled_used); + monitor_printf(mon, " signalled_used_valid: %s\n", + s->signalled_used_valid ? "true" : "false"); + if (s->has_last_avail_idx) { + monitor_printf(mon, " last_avail_idx: %d\n", + s->last_avail_idx); + } + if (s->has_shadow_avail_idx) { + monitor_printf(mon, " shadow_avail_idx: %d\n", + s->shadow_avail_idx); + } + monitor_printf(mon, " VRing:\n"); + monitor_printf(mon, " num: %"PRId32"\n", s->vring_num); + monitor_printf(mon, " num_default: %"PRId32"\n", + s->vring_num_default); + monitor_printf(mon, " align: %"PRId32"\n", + s->vring_align); + monitor_printf(mon, " desc: 0x%016"PRIx64"\n", + s->vring_desc); + monitor_printf(mon, " avail: 0x%016"PRIx64"\n", + s->vring_avail); + monitor_printf(mon, " used: 0x%016"PRIx64"\n", + s->vring_used); + + qapi_free_VirtQueueStatus(s); +} + +void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + int queue = qdict_get_int(qdict, "queue"); + int index = qdict_get_try_int(qdict, "index", -1); + VirtioQueueElement *e; + VirtioRingDescList *list; + + e = qmp_x_query_virtio_queue_element(path, queue, index != -1, + index, &err); + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " device_name: %s\n", e->name); + monitor_printf(mon, " index: %d\n", e->index); + monitor_printf(mon, " desc:\n"); + monitor_printf(mon, " descs:\n"); + + list = e->descs; + while (list) { + monitor_printf(mon, " addr 0x%"PRIx64" len %d", + list->value->addr, list->value->len); + if (list->value->flags) { + strList *flag = list->value->flags; + monitor_printf(mon, " ("); + while (flag) { + monitor_printf(mon, "%s", flag->value); + flag = flag->next; + if (flag) { + monitor_printf(mon, ", "); + } + } + monitor_printf(mon, ")"); + } + list = list->next; + if (list) { + monitor_printf(mon, ",\n"); + } + } + monitor_printf(mon, "\n"); + monitor_printf(mon, " avail:\n"); + monitor_printf(mon, " flags: %d\n", e->avail->flags); + monitor_printf(mon, " idx: %d\n", e->avail->idx); + monitor_printf(mon, " ring: %d\n", e->avail->ring); + monitor_printf(mon, " used:\n"); + monitor_printf(mon, " flags: %d\n", e->used->flags); + monitor_printf(mon, " idx: %d\n", e->used->idx); + + qapi_free_VirtioQueueElement(e); +} diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 4da6b7cccc..6b1d5358f7 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -23,7 +23,6 @@ #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qapi-commands-tpm.h" -#include "qapi/qapi-commands-virtio.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" @@ -533,311 +532,3 @@ exit: exit_no_print: error_free(err); } - -static void hmp_virtio_dump_protocols(Monitor *mon, - VhostDeviceProtocols *pcol) -{ - strList *pcol_list = pcol->protocols; - while (pcol_list) { - monitor_printf(mon, "\t%s", pcol_list->value); - pcol_list = pcol_list->next; - if (pcol_list != NULL) { - monitor_printf(mon, ",\n"); - } - } - monitor_printf(mon, "\n"); - if (pcol->has_unknown_protocols) { - monitor_printf(mon, " unknown-protocols(0x%016"PRIx64")\n", - pcol->unknown_protocols); - } -} - -static void hmp_virtio_dump_status(Monitor *mon, - VirtioDeviceStatus *status) -{ - strList *status_list = status->statuses; - while (status_list) { - monitor_printf(mon, "\t%s", status_list->value); - status_list = status_list->next; - if (status_list != NULL) { - monitor_printf(mon, ",\n"); - } - } - monitor_printf(mon, "\n"); - if (status->has_unknown_statuses) { - monitor_printf(mon, " unknown-statuses(0x%016"PRIx32")\n", - status->unknown_statuses); - } -} - -static void hmp_virtio_dump_features(Monitor *mon, - VirtioDeviceFeatures *features) -{ - strList *transport_list = features->transports; - while (transport_list) { - monitor_printf(mon, "\t%s", transport_list->value); - transport_list = transport_list->next; - if (transport_list != NULL) { - monitor_printf(mon, ",\n"); - } - } - - monitor_printf(mon, "\n"); - strList *list = features->dev_features; - if (list) { - while (list) { - monitor_printf(mon, "\t%s", list->value); - list = list->next; - if (list != NULL) { - monitor_printf(mon, ",\n"); - } - } - monitor_printf(mon, "\n"); - } - - if (features->has_unknown_dev_features) { - monitor_printf(mon, " unknown-features(0x%016"PRIx64")\n", - features->unknown_dev_features); - } -} - -void hmp_virtio_query(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - VirtioInfoList *list = qmp_x_query_virtio(&err); - VirtioInfoList *node; - - if (err != NULL) { - hmp_handle_error(mon, err); - return; - } - - if (list == NULL) { - monitor_printf(mon, "No VirtIO devices\n"); - return; - } - - node = list; - while (node) { - monitor_printf(mon, "%s [%s]\n", node->value->path, - node->value->name); - node = node->next; - } - qapi_free_VirtioInfoList(list); -} - -void hmp_virtio_status(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *path = qdict_get_try_str(qdict, "path"); - VirtioStatus *s = qmp_x_query_virtio_status(path, &err); - - if (err != NULL) { - hmp_handle_error(mon, err); - return; - } - - monitor_printf(mon, "%s:\n", path); - monitor_printf(mon, " device_name: %s %s\n", - s->name, s->vhost_dev ? "(vhost)" : ""); - monitor_printf(mon, " device_id: %d\n", s->device_id); - monitor_printf(mon, " vhost_started: %s\n", - s->vhost_started ? "true" : "false"); - monitor_printf(mon, " bus_name: %s\n", s->bus_name); - monitor_printf(mon, " broken: %s\n", - s->broken ? "true" : "false"); - monitor_printf(mon, " disabled: %s\n", - s->disabled ? "true" : "false"); - monitor_printf(mon, " disable_legacy_check: %s\n", - s->disable_legacy_check ? "true" : "false"); - monitor_printf(mon, " started: %s\n", - s->started ? "true" : "false"); - monitor_printf(mon, " use_started: %s\n", - s->use_started ? "true" : "false"); - monitor_printf(mon, " start_on_kick: %s\n", - s->start_on_kick ? "true" : "false"); - monitor_printf(mon, " use_guest_notifier_mask: %s\n", - s->use_guest_notifier_mask ? "true" : "false"); - monitor_printf(mon, " vm_running: %s\n", - s->vm_running ? "true" : "false"); - monitor_printf(mon, " num_vqs: %"PRId64"\n", s->num_vqs); - monitor_printf(mon, " queue_sel: %d\n", - s->queue_sel); - monitor_printf(mon, " isr: %d\n", s->isr); - monitor_printf(mon, " endianness: %s\n", - s->device_endian); - monitor_printf(mon, " status:\n"); - hmp_virtio_dump_status(mon, s->status); - monitor_printf(mon, " Guest features:\n"); - hmp_virtio_dump_features(mon, s->guest_features); - monitor_printf(mon, " Host features:\n"); - hmp_virtio_dump_features(mon, s->host_features); - monitor_printf(mon, " Backend features:\n"); - hmp_virtio_dump_features(mon, s->backend_features); - - if (s->vhost_dev) { - monitor_printf(mon, " VHost:\n"); - monitor_printf(mon, " nvqs: %d\n", - s->vhost_dev->nvqs); - monitor_printf(mon, " vq_index: %"PRId64"\n", - s->vhost_dev->vq_index); - monitor_printf(mon, " max_queues: %"PRId64"\n", - s->vhost_dev->max_queues); - monitor_printf(mon, " n_mem_sections: %"PRId64"\n", - s->vhost_dev->n_mem_sections); - monitor_printf(mon, " n_tmp_sections: %"PRId64"\n", - s->vhost_dev->n_tmp_sections); - monitor_printf(mon, " backend_cap: %"PRId64"\n", - s->vhost_dev->backend_cap); - monitor_printf(mon, " log_enabled: %s\n", - s->vhost_dev->log_enabled ? "true" : "false"); - monitor_printf(mon, " log_size: %"PRId64"\n", - s->vhost_dev->log_size); - monitor_printf(mon, " Features:\n"); - hmp_virtio_dump_features(mon, s->vhost_dev->features); - monitor_printf(mon, " Acked features:\n"); - hmp_virtio_dump_features(mon, s->vhost_dev->acked_features); - monitor_printf(mon, " Backend features:\n"); - hmp_virtio_dump_features(mon, s->vhost_dev->backend_features); - monitor_printf(mon, " Protocol features:\n"); - hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features); - } - - qapi_free_VirtioStatus(s); -} - -void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *path = qdict_get_try_str(qdict, "path"); - int queue = qdict_get_int(qdict, "queue"); - VirtVhostQueueStatus *s = - qmp_x_query_virtio_vhost_queue_status(path, queue, &err); - - if (err != NULL) { - hmp_handle_error(mon, err); - return; - } - - monitor_printf(mon, "%s:\n", path); - monitor_printf(mon, " device_name: %s (vhost)\n", - s->name); - monitor_printf(mon, " kick: %"PRId64"\n", s->kick); - monitor_printf(mon, " call: %"PRId64"\n", s->call); - monitor_printf(mon, " VRing:\n"); - monitor_printf(mon, " num: %"PRId64"\n", s->num); - monitor_printf(mon, " desc: 0x%016"PRIx64"\n", s->desc); - monitor_printf(mon, " desc_phys: 0x%016"PRIx64"\n", - s->desc_phys); - monitor_printf(mon, " desc_size: %"PRId32"\n", s->desc_size); - monitor_printf(mon, " avail: 0x%016"PRIx64"\n", s->avail); - monitor_printf(mon, " avail_phys: 0x%016"PRIx64"\n", - s->avail_phys); - monitor_printf(mon, " avail_size: %"PRId32"\n", s->avail_size); - monitor_printf(mon, " used: 0x%016"PRIx64"\n", s->used); - monitor_printf(mon, " used_phys: 0x%016"PRIx64"\n", - s->used_phys); - monitor_printf(mon, " used_size: %"PRId32"\n", s->used_size); - - qapi_free_VirtVhostQueueStatus(s); -} - -void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *path = qdict_get_try_str(qdict, "path"); - int queue = qdict_get_int(qdict, "queue"); - VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err); - - if (err != NULL) { - hmp_handle_error(mon, err); - return; - } - - monitor_printf(mon, "%s:\n", path); - monitor_printf(mon, " device_name: %s\n", s->name); - monitor_printf(mon, " queue_index: %d\n", s->queue_index); - monitor_printf(mon, " inuse: %d\n", s->inuse); - monitor_printf(mon, " used_idx: %d\n", s->used_idx); - monitor_printf(mon, " signalled_used: %d\n", - s->signalled_used); - monitor_printf(mon, " signalled_used_valid: %s\n", - s->signalled_used_valid ? "true" : "false"); - if (s->has_last_avail_idx) { - monitor_printf(mon, " last_avail_idx: %d\n", - s->last_avail_idx); - } - if (s->has_shadow_avail_idx) { - monitor_printf(mon, " shadow_avail_idx: %d\n", - s->shadow_avail_idx); - } - monitor_printf(mon, " VRing:\n"); - monitor_printf(mon, " num: %"PRId32"\n", s->vring_num); - monitor_printf(mon, " num_default: %"PRId32"\n", - s->vring_num_default); - monitor_printf(mon, " align: %"PRId32"\n", - s->vring_align); - monitor_printf(mon, " desc: 0x%016"PRIx64"\n", - s->vring_desc); - monitor_printf(mon, " avail: 0x%016"PRIx64"\n", - s->vring_avail); - monitor_printf(mon, " used: 0x%016"PRIx64"\n", - s->vring_used); - - qapi_free_VirtQueueStatus(s); -} - -void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - const char *path = qdict_get_try_str(qdict, "path"); - int queue = qdict_get_int(qdict, "queue"); - int index = qdict_get_try_int(qdict, "index", -1); - VirtioQueueElement *e; - VirtioRingDescList *list; - - e = qmp_x_query_virtio_queue_element(path, queue, index != -1, - index, &err); - if (err != NULL) { - hmp_handle_error(mon, err); - return; - } - - monitor_printf(mon, "%s:\n", path); - monitor_printf(mon, " device_name: %s\n", e->name); - monitor_printf(mon, " index: %d\n", e->index); - monitor_printf(mon, " desc:\n"); - monitor_printf(mon, " descs:\n"); - - list = e->descs; - while (list) { - monitor_printf(mon, " addr 0x%"PRIx64" len %d", - list->value->addr, list->value->len); - if (list->value->flags) { - strList *flag = list->value->flags; - monitor_printf(mon, " ("); - while (flag) { - monitor_printf(mon, "%s", flag->value); - flag = flag->next; - if (flag) { - monitor_printf(mon, ", "); - } - } - monitor_printf(mon, ")"); - } - list = list->next; - if (list) { - monitor_printf(mon, ",\n"); - } - } - monitor_printf(mon, "\n"); - monitor_printf(mon, " avail:\n"); - monitor_printf(mon, " flags: %d\n", e->avail->flags); - monitor_printf(mon, " idx: %d\n", e->avail->idx); - monitor_printf(mon, " ring: %d\n", e->avail->ring); - monitor_printf(mon, " used:\n"); - monitor_printf(mon, " flags: %d\n", e->used->flags); - monitor_printf(mon, " idx: %d\n", e->used->idx); - - qapi_free_VirtioQueueElement(e); -} From 0801062c1b891c5d152a04be10abd5d5af4a9c42 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:34 +0100 Subject: [PATCH 457/814] tpm: Move HMP commands from monitor/ to softmmu/ This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "TPM". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-21-armbru@redhat.com> Reviewed-by: Stefan Berger --- MAINTAINERS | 2 +- monitor/hmp-cmds.c | 54 ----------------------------------- softmmu/meson.build | 1 + softmmu/tpm-hmp-cmds.c | 65 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 softmmu/tpm-hmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index 3bd4d101d3..dab4def753 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3067,7 +3067,7 @@ T: git https://github.com/stefanha/qemu.git tracing TPM M: Stefan Berger S: Maintained -F: softmmu/tpm.c +F: softmmu/tpm* F: hw/tpm/* F: include/hw/acpi/tpm.h F: include/sysemu/tpm* diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 6b1d5358f7..81f63fa8ec 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -22,7 +22,6 @@ #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" -#include "qapi/qapi-commands-tpm.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" @@ -126,59 +125,6 @@ void hmp_info_pic(Monitor *mon, const QDict *qdict) hmp_info_pic_foreach, mon); } -void hmp_info_tpm(Monitor *mon, const QDict *qdict) -{ -#ifdef CONFIG_TPM - TPMInfoList *info_list, *info; - Error *err = NULL; - unsigned int c = 0; - TPMPassthroughOptions *tpo; - TPMEmulatorOptions *teo; - - info_list = qmp_query_tpm(&err); - if (err) { - monitor_printf(mon, "TPM device not supported\n"); - error_free(err); - return; - } - - if (info_list) { - monitor_printf(mon, "TPM device:\n"); - } - - for (info = info_list; info; info = info->next) { - TPMInfo *ti = info->value; - monitor_printf(mon, " tpm%d: model=%s\n", - c, TpmModel_str(ti->model)); - - monitor_printf(mon, " \\ %s: type=%s", - ti->id, TpmType_str(ti->options->type)); - - switch (ti->options->type) { - case TPM_TYPE_PASSTHROUGH: - tpo = ti->options->u.passthrough.data; - monitor_printf(mon, "%s%s%s%s", - tpo->path ? ",path=" : "", - tpo->path ?: "", - tpo->cancel_path ? ",cancel-path=" : "", - tpo->cancel_path ?: ""); - break; - case TPM_TYPE_EMULATOR: - teo = ti->options->u.emulator.data; - monitor_printf(mon, ",chardev=%s", teo->chardev); - break; - case TPM_TYPE__MAX: - break; - } - monitor_printf(mon, "\n"); - c++; - } - qapi_free_TPMInfoList(info_list); -#else - monitor_printf(mon, "TPM device not supported\n"); -#endif /* CONFIG_TPM */ -} - void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/softmmu/meson.build b/softmmu/meson.build index 3272af1f31..efbf4ec029 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -25,6 +25,7 @@ softmmu_ss.add(files( 'rtc.c', 'runstate-action.c', 'runstate.c', + 'tpm-hmp-cmds.c', 'vl.c', ), sdl, libpmem, libdaxctl) diff --git a/softmmu/tpm-hmp-cmds.c b/softmmu/tpm-hmp-cmds.c new file mode 100644 index 0000000000..9ed6ad6c4d --- /dev/null +++ b/softmmu/tpm-hmp-cmds.c @@ -0,0 +1,65 @@ +/* + * HMP commands related to TPM + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-commands-tpm.h" +#include "monitor/monitor.h" +#include "monitor/hmp.h" +#include "qapi/error.h" + +void hmp_info_tpm(Monitor *mon, const QDict *qdict) +{ +#ifdef CONFIG_TPM + TPMInfoList *info_list, *info; + Error *err = NULL; + unsigned int c = 0; + TPMPassthroughOptions *tpo; + TPMEmulatorOptions *teo; + + info_list = qmp_query_tpm(&err); + if (err) { + monitor_printf(mon, "TPM device not supported\n"); + error_free(err); + return; + } + + if (info_list) { + monitor_printf(mon, "TPM device:\n"); + } + + for (info = info_list; info; info = info->next) { + TPMInfo *ti = info->value; + monitor_printf(mon, " tpm%d: model=%s\n", + c, TpmModel_str(ti->model)); + + monitor_printf(mon, " \\ %s: type=%s", + ti->id, TpmType_str(ti->options->type)); + + switch (ti->options->type) { + case TPM_TYPE_PASSTHROUGH: + tpo = ti->options->u.passthrough.data; + monitor_printf(mon, "%s%s%s%s", + tpo->path ? ",path=" : "", + tpo->path ?: "", + tpo->cancel_path ? ",cancel-path=" : "", + tpo->cancel_path ?: ""); + break; + case TPM_TYPE_EMULATOR: + teo = ti->options->u.emulator.data; + monitor_printf(mon, ",chardev=%s", teo->chardev); + break; + case TPM_TYPE__MAX: + break; + } + monitor_printf(mon, "\n"); + c++; + } + qapi_free_TPMInfoList(info_list); +#else + monitor_printf(mon, "TPM device not supported\n"); +#endif /* CONFIG_TPM */ +} From bab46b8180fdb0cf9a7adb7598f371d4457f51ca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:35 +0100 Subject: [PATCH 458/814] runstate: Move HMP commands from monitor/ to softmmu/ This moves these commands from MAINTAINERS section "Human Monitor (HMP)" and "QMP" to "Main loop". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-22-armbru@redhat.com> --- MAINTAINERS | 3 +- include/monitor/hmp.h | 2 + monitor/hmp-cmds.c | 20 --------- monitor/misc.c | 42 ------------------- softmmu/meson.build | 1 + softmmu/runstate-hmp-cmds.c | 82 +++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 64 deletions(-) create mode 100644 softmmu/runstate-hmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index dab4def753..b2f1d2518b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2804,8 +2804,7 @@ F: softmmu/cpus.c F: softmmu/cpu-throttle.c F: softmmu/cpu-timers.c F: softmmu/icount.c -F: softmmu/runstate-action.c -F: softmmu/runstate.c +F: softmmu/runstate* F: qapi/run-state.json Read, Copy, Update (RCU) diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index a248ee9ed1..941da9fde6 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -156,6 +156,8 @@ void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict); void hmp_human_readable_text_helper(Monitor *mon, HumanReadableText *(*qmp_handler)(Error **)); void hmp_info_stats(Monitor *mon, const QDict *qdict); +void hmp_singlestep(Monitor *mon, const QDict *qdict); +void hmp_watchdog_action(Monitor *mon, const QDict *qdict); void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict); void hmp_info_capture(Monitor *mon, const QDict *qdict); void hmp_stopcapture(Monitor *mon, const QDict *qdict); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 81f63fa8ec..34e98b0e0b 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -20,7 +20,6 @@ #include "qapi/error.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-stats.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" @@ -80,25 +79,6 @@ void hmp_info_version(Monitor *mon, const QDict *qdict) qapi_free_VersionInfo(info); } -void hmp_info_status(Monitor *mon, const QDict *qdict) -{ - StatusInfo *info; - - info = qmp_query_status(NULL); - - monitor_printf(mon, "VM status: %s%s", - info->running ? "running" : "paused", - info->singlestep ? " (single step mode)" : ""); - - if (!info->running && info->status != RUN_STATE_PAUSED) { - monitor_printf(mon, " (%s)", RunState_str(info->status)); - } - - monitor_printf(mon, "\n"); - - qapi_free_StatusInfo(info); -} - static int hmp_info_pic_foreach(Object *obj, void *opaque) { InterruptStatsProvider *intc; diff --git a/monitor/misc.c b/monitor/misc.c index ff3002a880..a2584df0ca 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -43,7 +43,6 @@ #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-init-commands.h" #include "qapi/error.h" @@ -319,18 +318,6 @@ static void hmp_log(Monitor *mon, const QDict *qdict) } } -static void hmp_singlestep(Monitor *mon, const QDict *qdict) -{ - const char *option = qdict_get_try_str(qdict, "option"); - if (!option || !strcmp(option, "on")) { - singlestep = 1; - } else if (!strcmp(option, "off")) { - singlestep = 0; - } else { - monitor_printf(mon, "unexpected option %s\n", option); - } -} - static void hmp_gdbserver(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_try_str(qdict, "device"); @@ -349,22 +336,6 @@ static void hmp_gdbserver(Monitor *mon, const QDict *qdict) } } -static void hmp_watchdog_action(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - WatchdogAction action; - char *qapi_value; - - qapi_value = g_ascii_strdown(qdict_get_str(qdict, "action"), -1); - action = qapi_enum_parse(&WatchdogAction_lookup, qapi_value, -1, &err); - g_free(qapi_value); - if (err) { - hmp_handle_error(mon, err); - return; - } - qmp_watchdog_set_action(action, &error_abort); -} - static void monitor_printc(Monitor *mon, int c) { monitor_printf(mon, "'"); @@ -1317,19 +1288,6 @@ void device_del_completion(ReadLineState *rs, int nb_args, const char *str) peripheral_device_del_completion(rs, str); } -void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) -{ - int i; - - if (nb_args != 2) { - return; - } - readline_set_completion_index(rs, strlen(str)); - for (i = 0; i < WATCHDOG_ACTION__MAX; i++) { - readline_add_completion_of(rs, str, WatchdogAction_str(i)); - } -} - static int compare_mon_cmd(const void *a, const void *b) { diff --git a/softmmu/meson.build b/softmmu/meson.build index efbf4ec029..1828db149c 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -24,6 +24,7 @@ softmmu_ss.add(files( 'qdev-monitor.c', 'rtc.c', 'runstate-action.c', + 'runstate-hmp-cmds.c', 'runstate.c', 'tpm-hmp-cmds.c', 'vl.c', diff --git a/softmmu/runstate-hmp-cmds.c b/softmmu/runstate-hmp-cmds.c new file mode 100644 index 0000000000..d55a7d4db8 --- /dev/null +++ b/softmmu/runstate-hmp-cmds.c @@ -0,0 +1,82 @@ +/* + * HMP commands related to run state + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "exec/cpu-common.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-run-state.h" +#include "qapi/qmp/qdict.h" + +void hmp_info_status(Monitor *mon, const QDict *qdict) +{ + StatusInfo *info; + + info = qmp_query_status(NULL); + + monitor_printf(mon, "VM status: %s%s", + info->running ? "running" : "paused", + info->singlestep ? " (single step mode)" : ""); + + if (!info->running && info->status != RUN_STATE_PAUSED) { + monitor_printf(mon, " (%s)", RunState_str(info->status)); + } + + monitor_printf(mon, "\n"); + + qapi_free_StatusInfo(info); +} + +void hmp_singlestep(Monitor *mon, const QDict *qdict) +{ + const char *option = qdict_get_try_str(qdict, "option"); + if (!option || !strcmp(option, "on")) { + singlestep = 1; + } else if (!strcmp(option, "off")) { + singlestep = 0; + } else { + monitor_printf(mon, "unexpected option %s\n", option); + } +} + +void hmp_watchdog_action(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + WatchdogAction action; + char *qapi_value; + + qapi_value = g_ascii_strdown(qdict_get_str(qdict, "action"), -1); + action = qapi_enum_parse(&WatchdogAction_lookup, qapi_value, -1, &err); + g_free(qapi_value); + if (err) { + hmp_handle_error(mon, err); + return; + } + qmp_watchdog_set_action(action, &error_abort); +} + +void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str) +{ + int i; + + if (nb_args != 2) { + return; + } + readline_set_completion_index(rs, strlen(str)); + for (i = 0; i < WATCHDOG_ACTION__MAX; i++) { + readline_add_completion_of(rs, str, WatchdogAction_str(i)); + } +} From aa09b3d5f8e2819d53a6fd81e655ddb3ef107a47 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:36 +0100 Subject: [PATCH 459/814] stats: Move QMP commands from monitor/ to stats/ This moves these commands from MAINTAINERS section "QMP" to new section "Stats". Status is Orphan. Volunteers welcome! Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-23-armbru@redhat.com> --- MAINTAINERS | 5 + accel/kvm/kvm-all.c | 2 +- include/{monitor => sysemu}/stats.h | 0 meson.build | 1 + monitor/qmp-cmds.c | 152 -------------------------- stats/meson.build | 1 + stats/stats-qmp-cmds.c | 162 ++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 153 deletions(-) rename include/{monitor => sysemu}/stats.h (100%) create mode 100644 stats/meson.build create mode 100644 stats/stats-qmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index b2f1d2518b..b377ac1476 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3038,6 +3038,11 @@ F: net/slirp.c F: include/net/slirp.h T: git https://people.debian.org/~sthibault/qemu.git slirp +Stats +S: Orphan +F: include/sysemu/stats.h +F: stats/ + Streams M: Edgar E. Iglesias S: Maintained diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 7e6a6076b1..9b26582655 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -50,7 +50,7 @@ #include "qemu/range.h" #include "hw/boards.h" -#include "monitor/stats.h" +#include "sysemu/stats.h" /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD diff --git a/include/monitor/stats.h b/include/sysemu/stats.h similarity index 100% rename from include/monitor/stats.h rename to include/sysemu/stats.h diff --git a/meson.build b/meson.build index 6d3b665629..57b35d721e 100644 --- a/meson.build +++ b/meson.build @@ -3132,6 +3132,7 @@ subdir('monitor') subdir('net') subdir('replay') subdir('semihosting') +subdir('stats') subdir('tcg') subdir('fpu') subdir('accel') diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 4a8d1e9a15..ab23e52f97 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -25,13 +25,11 @@ #include "qapi/qapi-commands-acpi.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-stats.h" #include "qapi/type-helpers.h" #include "hw/mem/memory-device.h" #include "hw/acpi/acpi_dev_interface.h" #include "hw/intc/intc.h" #include "hw/rdma/rdma.h" -#include "monitor/stats.h" NameInfo *qmp_query_name(Error **errp) { @@ -174,153 +172,3 @@ ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) return head; } - -typedef struct StatsCallbacks { - StatsProvider provider; - StatRetrieveFunc *stats_cb; - SchemaRetrieveFunc *schemas_cb; - QTAILQ_ENTRY(StatsCallbacks) next; -} StatsCallbacks; - -static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = - QTAILQ_HEAD_INITIALIZER(stats_callbacks); - -void add_stats_callbacks(StatsProvider provider, - StatRetrieveFunc *stats_fn, - SchemaRetrieveFunc *schemas_fn) -{ - StatsCallbacks *entry = g_new(StatsCallbacks, 1); - entry->provider = provider; - entry->stats_cb = stats_fn; - entry->schemas_cb = schemas_fn; - - QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); -} - -static bool invoke_stats_cb(StatsCallbacks *entry, - StatsResultList **stats_results, - StatsFilter *filter, StatsRequest *request, - Error **errp) -{ - ERRP_GUARD(); - strList *targets = NULL; - strList *names = NULL; - - if (request) { - if (request->provider != entry->provider) { - return true; - } - if (request->has_names && !request->names) { - return true; - } - names = request->has_names ? request->names : NULL; - } - - switch (filter->target) { - case STATS_TARGET_VM: - break; - case STATS_TARGET_VCPU: - if (filter->u.vcpu.has_vcpus) { - if (!filter->u.vcpu.vcpus) { - /* No targets allowed? Return no statistics. */ - return true; - } - targets = filter->u.vcpu.vcpus; - } - break; - default: - abort(); - } - - entry->stats_cb(stats_results, filter->target, names, targets, errp); - if (*errp) { - qapi_free_StatsResultList(*stats_results); - *stats_results = NULL; - return false; - } - return true; -} - -StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) -{ - StatsResultList *stats_results = NULL; - StatsCallbacks *entry; - StatsRequestList *request; - - QTAILQ_FOREACH(entry, &stats_callbacks, next) { - if (filter->has_providers) { - for (request = filter->providers; request; request = request->next) { - if (!invoke_stats_cb(entry, &stats_results, filter, - request->value, errp)) { - break; - } - } - } else { - if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { - break; - } - } - } - - return stats_results; -} - -StatsSchemaList *qmp_query_stats_schemas(bool has_provider, - StatsProvider provider, - Error **errp) -{ - ERRP_GUARD(); - StatsSchemaList *stats_results = NULL; - StatsCallbacks *entry; - - QTAILQ_FOREACH(entry, &stats_callbacks, next) { - if (!has_provider || provider == entry->provider) { - entry->schemas_cb(&stats_results, errp); - if (*errp) { - qapi_free_StatsSchemaList(stats_results); - return NULL; - } - } - } - - return stats_results; -} - -void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, - const char *qom_path, StatsList *stats_list) -{ - StatsResult *entry = g_new0(StatsResult, 1); - - entry->provider = provider; - entry->qom_path = g_strdup(qom_path); - entry->stats = stats_list; - - QAPI_LIST_PREPEND(*stats_results, entry); -} - -void add_stats_schema(StatsSchemaList **schema_results, - StatsProvider provider, StatsTarget target, - StatsSchemaValueList *stats_list) -{ - StatsSchema *entry = g_new0(StatsSchema, 1); - - entry->provider = provider; - entry->target = target; - entry->stats = stats_list; - QAPI_LIST_PREPEND(*schema_results, entry); -} - -bool apply_str_list_filter(const char *string, strList *list) -{ - strList *str_list = NULL; - - if (!list) { - return true; - } - for (str_list = list; str_list; str_list = str_list->next) { - if (g_str_equal(string, str_list->value)) { - return true; - } - } - return false; -} diff --git a/stats/meson.build b/stats/meson.build new file mode 100644 index 0000000000..4ddb4d096b --- /dev/null +++ b/stats/meson.build @@ -0,0 +1 @@ +softmmu_ss.add(files('stats-qmp-cmds.c')) diff --git a/stats/stats-qmp-cmds.c b/stats/stats-qmp-cmds.c new file mode 100644 index 0000000000..bc973747fb --- /dev/null +++ b/stats/stats-qmp-cmds.c @@ -0,0 +1,162 @@ +/* + * QMP commands related to stats + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "sysemu/stats.h" +#include "qapi/qapi-commands-stats.h" +#include "qemu/queue.h" +#include "qapi/error.h" + +typedef struct StatsCallbacks { + StatsProvider provider; + StatRetrieveFunc *stats_cb; + SchemaRetrieveFunc *schemas_cb; + QTAILQ_ENTRY(StatsCallbacks) next; +} StatsCallbacks; + +static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = + QTAILQ_HEAD_INITIALIZER(stats_callbacks); + +void add_stats_callbacks(StatsProvider provider, + StatRetrieveFunc *stats_fn, + SchemaRetrieveFunc *schemas_fn) +{ + StatsCallbacks *entry = g_new(StatsCallbacks, 1); + entry->provider = provider; + entry->stats_cb = stats_fn; + entry->schemas_cb = schemas_fn; + + QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); +} + +static bool invoke_stats_cb(StatsCallbacks *entry, + StatsResultList **stats_results, + StatsFilter *filter, StatsRequest *request, + Error **errp) +{ + ERRP_GUARD(); + strList *targets = NULL; + strList *names = NULL; + + if (request) { + if (request->provider != entry->provider) { + return true; + } + if (request->has_names && !request->names) { + return true; + } + names = request->has_names ? request->names : NULL; + } + + switch (filter->target) { + case STATS_TARGET_VM: + break; + case STATS_TARGET_VCPU: + if (filter->u.vcpu.has_vcpus) { + if (!filter->u.vcpu.vcpus) { + /* No targets allowed? Return no statistics. */ + return true; + } + targets = filter->u.vcpu.vcpus; + } + break; + default: + abort(); + } + + entry->stats_cb(stats_results, filter->target, names, targets, errp); + if (*errp) { + qapi_free_StatsResultList(*stats_results); + *stats_results = NULL; + return false; + } + return true; +} + +StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) +{ + StatsResultList *stats_results = NULL; + StatsCallbacks *entry; + StatsRequestList *request; + + QTAILQ_FOREACH(entry, &stats_callbacks, next) { + if (filter->has_providers) { + for (request = filter->providers; request; request = request->next) { + if (!invoke_stats_cb(entry, &stats_results, filter, + request->value, errp)) { + break; + } + } + } else { + if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { + break; + } + } + } + + return stats_results; +} + +StatsSchemaList *qmp_query_stats_schemas(bool has_provider, + StatsProvider provider, + Error **errp) +{ + ERRP_GUARD(); + StatsSchemaList *stats_results = NULL; + StatsCallbacks *entry; + + QTAILQ_FOREACH(entry, &stats_callbacks, next) { + if (!has_provider || provider == entry->provider) { + entry->schemas_cb(&stats_results, errp); + if (*errp) { + qapi_free_StatsSchemaList(stats_results); + return NULL; + } + } + } + + return stats_results; +} + +void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, + const char *qom_path, StatsList *stats_list) +{ + StatsResult *entry = g_new0(StatsResult, 1); + + entry->provider = provider; + entry->qom_path = g_strdup(qom_path); + entry->stats = stats_list; + + QAPI_LIST_PREPEND(*stats_results, entry); +} + +void add_stats_schema(StatsSchemaList **schema_results, + StatsProvider provider, StatsTarget target, + StatsSchemaValueList *stats_list) +{ + StatsSchema *entry = g_new0(StatsSchema, 1); + + entry->provider = provider; + entry->target = target; + entry->stats = stats_list; + QAPI_LIST_PREPEND(*schema_results, entry); +} + +bool apply_str_list_filter(const char *string, strList *list) +{ + strList *str_list = NULL; + + if (!list) { + return true; + } + for (str_list = list; str_list; str_list = str_list->next) { + if (g_str_equal(string, str_list->value)) { + return true; + } + } + return false; +} From 6a5fcf6c1e06561a14b4456807a5c8f8cc3f936a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:37 +0100 Subject: [PATCH 460/814] stats: Move HMP commands from monitor/ to stats/ This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to section "Stats". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-24-armbru@redhat.com> --- monitor/hmp-cmds.c | 234 -------------------------------------- stats/meson.build | 2 +- stats/stats-hmp-cmds.c | 247 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 235 deletions(-) create mode 100644 stats/stats-hmp-cmds.c diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 34e98b0e0b..8a3d56bcde 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -20,11 +20,9 @@ #include "qapi/error.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-stats.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" -#include "hw/core/cpu.h" #include "hw/intc/intc.h" bool hmp_handle_error(Monitor *mon, Error *err) @@ -226,235 +224,3 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict) qapi_free_IOThreadInfoList(info_list); } - -static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) -{ - const char *unit = NULL; - monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type), - value->has_unit || value->exponent ? ", " : ""); - - if (value->has_unit) { - if (value->unit == STATS_UNIT_SECONDS) { - unit = "s"; - } else if (value->unit == STATS_UNIT_BYTES) { - unit = "B"; - } - } - - if (unit && value->base == 10 && - value->exponent >= -18 && value->exponent <= 18 && - value->exponent % 3 == 0) { - monitor_puts(mon, si_prefix(value->exponent)); - } else if (unit && value->base == 2 && - value->exponent >= 0 && value->exponent <= 60 && - value->exponent % 10 == 0) { - - monitor_puts(mon, iec_binary_prefix(value->exponent)); - } else if (value->exponent) { - /* Use exponential notation and write the unit's English name */ - monitor_printf(mon, "* %d^%d%s", - value->base, value->exponent, - value->has_unit ? " " : ""); - unit = NULL; - } - - if (value->has_unit) { - monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit)); - } - - /* Print bucket size for linear histograms */ - if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) { - monitor_printf(mon, ", bucket size=%d", value->bucket_size); - } - monitor_printf(mon, ")"); -} - -static StatsSchemaValueList *find_schema_value_list( - StatsSchemaList *list, StatsProvider provider, - StatsTarget target) -{ - StatsSchemaList *node; - - for (node = list; node; node = node->next) { - if (node->value->provider == provider && - node->value->target == target) { - return node->value->stats; - } - } - return NULL; -} - -static void print_stats_results(Monitor *mon, StatsTarget target, - bool show_provider, - StatsResult *result, - StatsSchemaList *schema) -{ - /* Find provider schema */ - StatsSchemaValueList *schema_value_list = - find_schema_value_list(schema, result->provider, target); - StatsList *stats_list; - - if (!schema_value_list) { - monitor_printf(mon, "failed to find schema list for %s\n", - StatsProvider_str(result->provider)); - return; - } - - if (show_provider) { - monitor_printf(mon, "provider: %s\n", - StatsProvider_str(result->provider)); - } - - for (stats_list = result->stats; stats_list; - stats_list = stats_list->next, - schema_value_list = schema_value_list->next) { - - Stats *stats = stats_list->value; - StatsValue *stats_value = stats->value; - StatsSchemaValue *schema_value = schema_value_list->value; - - /* Find schema entry */ - while (!g_str_equal(stats->name, schema_value->name)) { - if (!schema_value_list->next) { - monitor_printf(mon, "failed to find schema entry for %s\n", - stats->name); - return; - } - schema_value_list = schema_value_list->next; - schema_value = schema_value_list->value; - } - - print_stats_schema_value(mon, schema_value); - - if (stats_value->type == QTYPE_QNUM) { - monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar); - } else if (stats_value->type == QTYPE_QBOOL) { - monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no"); - } else if (stats_value->type == QTYPE_QLIST) { - uint64List *list; - int i; - - monitor_printf(mon, ": "); - for (list = stats_value->u.list, i = 1; - list; - list = list->next, i++) { - monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value); - } - monitor_printf(mon, "\n"); - } - } -} - -/* Create the StatsFilter that is needed for an "info stats" invocation. */ -static StatsFilter *stats_filter(StatsTarget target, const char *names, - int cpu_index, StatsProvider provider) -{ - StatsFilter *filter = g_malloc0(sizeof(*filter)); - StatsProvider provider_idx; - StatsRequestList *request_list = NULL; - - filter->target = target; - switch (target) { - case STATS_TARGET_VM: - break; - case STATS_TARGET_VCPU: - { - strList *vcpu_list = NULL; - CPUState *cpu = qemu_get_cpu(cpu_index); - char *canonical_path = object_get_canonical_path(OBJECT(cpu)); - - QAPI_LIST_PREPEND(vcpu_list, canonical_path); - filter->u.vcpu.has_vcpus = true; - filter->u.vcpu.vcpus = vcpu_list; - break; - } - default: - break; - } - - if (!names && provider == STATS_PROVIDER__MAX) { - return filter; - } - - /* - * "info stats" can only query either one or all the providers. Querying - * by name, but not by provider, requires the creation of one filter per - * provider. - */ - for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) { - if (provider == STATS_PROVIDER__MAX || provider == provider_idx) { - StatsRequest *request = g_new0(StatsRequest, 1); - request->provider = provider_idx; - if (names && !g_str_equal(names, "*")) { - request->has_names = true; - request->names = hmp_split_at_comma(names); - } - QAPI_LIST_PREPEND(request_list, request); - } - } - - filter->has_providers = true; - filter->providers = request_list; - return filter; -} - -void hmp_info_stats(Monitor *mon, const QDict *qdict) -{ - const char *target_str = qdict_get_str(qdict, "target"); - const char *provider_str = qdict_get_try_str(qdict, "provider"); - const char *names = qdict_get_try_str(qdict, "names"); - - StatsProvider provider = STATS_PROVIDER__MAX; - StatsTarget target; - Error *err = NULL; - g_autoptr(StatsSchemaList) schema = NULL; - g_autoptr(StatsResultList) stats = NULL; - g_autoptr(StatsFilter) filter = NULL; - StatsResultList *entry; - - target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err); - if (err) { - monitor_printf(mon, "invalid stats target %s\n", target_str); - goto exit_no_print; - } - if (provider_str) { - provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err); - if (err) { - monitor_printf(mon, "invalid stats provider %s\n", provider_str); - goto exit_no_print; - } - } - - schema = qmp_query_stats_schemas(provider_str ? true : false, - provider, &err); - if (err) { - goto exit; - } - - switch (target) { - case STATS_TARGET_VM: - filter = stats_filter(target, names, -1, provider); - break; - case STATS_TARGET_VCPU: {} - int cpu_index = monitor_get_cpu_index(mon); - filter = stats_filter(target, names, cpu_index, provider); - break; - default: - abort(); - } - - stats = qmp_query_stats(filter, &err); - if (err) { - goto exit; - } - for (entry = stats; entry; entry = entry->next) { - print_stats_results(mon, target, provider_str == NULL, entry->value, schema); - } - -exit: - if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - } -exit_no_print: - error_free(err); -} diff --git a/stats/meson.build b/stats/meson.build index 4ddb4d096b..c4153f979e 100644 --- a/stats/meson.build +++ b/stats/meson.build @@ -1 +1 @@ -softmmu_ss.add(files('stats-qmp-cmds.c')) +softmmu_ss.add(files('stats-hmp-cmds.c', 'stats-qmp-cmds.c')) diff --git a/stats/stats-hmp-cmds.c b/stats/stats-hmp-cmds.c new file mode 100644 index 0000000000..531e35d128 --- /dev/null +++ b/stats/stats-hmp-cmds.c @@ -0,0 +1,247 @@ +/* + * HMP commands related to stats + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-commands-stats.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qemu/cutils.h" +#include "hw/core/cpu.h" +#include "qapi/qmp/qdict.h" +#include "qapi/error.h" + +static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value) +{ + const char *unit = NULL; + monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type), + value->has_unit || value->exponent ? ", " : ""); + + if (value->has_unit) { + if (value->unit == STATS_UNIT_SECONDS) { + unit = "s"; + } else if (value->unit == STATS_UNIT_BYTES) { + unit = "B"; + } + } + + if (unit && value->base == 10 && + value->exponent >= -18 && value->exponent <= 18 && + value->exponent % 3 == 0) { + monitor_puts(mon, si_prefix(value->exponent)); + } else if (unit && value->base == 2 && + value->exponent >= 0 && value->exponent <= 60 && + value->exponent % 10 == 0) { + + monitor_puts(mon, iec_binary_prefix(value->exponent)); + } else if (value->exponent) { + /* Use exponential notation and write the unit's English name */ + monitor_printf(mon, "* %d^%d%s", + value->base, value->exponent, + value->has_unit ? " " : ""); + unit = NULL; + } + + if (value->has_unit) { + monitor_puts(mon, unit ? unit : StatsUnit_str(value->unit)); + } + + /* Print bucket size for linear histograms */ + if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) { + monitor_printf(mon, ", bucket size=%d", value->bucket_size); + } + monitor_printf(mon, ")"); +} + +static StatsSchemaValueList *find_schema_value_list( + StatsSchemaList *list, StatsProvider provider, + StatsTarget target) +{ + StatsSchemaList *node; + + for (node = list; node; node = node->next) { + if (node->value->provider == provider && + node->value->target == target) { + return node->value->stats; + } + } + return NULL; +} + +static void print_stats_results(Monitor *mon, StatsTarget target, + bool show_provider, + StatsResult *result, + StatsSchemaList *schema) +{ + /* Find provider schema */ + StatsSchemaValueList *schema_value_list = + find_schema_value_list(schema, result->provider, target); + StatsList *stats_list; + + if (!schema_value_list) { + monitor_printf(mon, "failed to find schema list for %s\n", + StatsProvider_str(result->provider)); + return; + } + + if (show_provider) { + monitor_printf(mon, "provider: %s\n", + StatsProvider_str(result->provider)); + } + + for (stats_list = result->stats; stats_list; + stats_list = stats_list->next, + schema_value_list = schema_value_list->next) { + + Stats *stats = stats_list->value; + StatsValue *stats_value = stats->value; + StatsSchemaValue *schema_value = schema_value_list->value; + + /* Find schema entry */ + while (!g_str_equal(stats->name, schema_value->name)) { + if (!schema_value_list->next) { + monitor_printf(mon, "failed to find schema entry for %s\n", + stats->name); + return; + } + schema_value_list = schema_value_list->next; + schema_value = schema_value_list->value; + } + + print_stats_schema_value(mon, schema_value); + + if (stats_value->type == QTYPE_QNUM) { + monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar); + } else if (stats_value->type == QTYPE_QBOOL) { + monitor_printf(mon, ": %s\n", stats_value->u.boolean ? "yes" : "no"); + } else if (stats_value->type == QTYPE_QLIST) { + uint64List *list; + int i; + + monitor_printf(mon, ": "); + for (list = stats_value->u.list, i = 1; + list; + list = list->next, i++) { + monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value); + } + monitor_printf(mon, "\n"); + } + } +} + +/* Create the StatsFilter that is needed for an "info stats" invocation. */ +static StatsFilter *stats_filter(StatsTarget target, const char *names, + int cpu_index, StatsProvider provider) +{ + StatsFilter *filter = g_malloc0(sizeof(*filter)); + StatsProvider provider_idx; + StatsRequestList *request_list = NULL; + + filter->target = target; + switch (target) { + case STATS_TARGET_VM: + break; + case STATS_TARGET_VCPU: + { + strList *vcpu_list = NULL; + CPUState *cpu = qemu_get_cpu(cpu_index); + char *canonical_path = object_get_canonical_path(OBJECT(cpu)); + + QAPI_LIST_PREPEND(vcpu_list, canonical_path); + filter->u.vcpu.has_vcpus = true; + filter->u.vcpu.vcpus = vcpu_list; + break; + } + default: + break; + } + + if (!names && provider == STATS_PROVIDER__MAX) { + return filter; + } + + /* + * "info stats" can only query either one or all the providers. Querying + * by name, but not by provider, requires the creation of one filter per + * provider. + */ + for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) { + if (provider == STATS_PROVIDER__MAX || provider == provider_idx) { + StatsRequest *request = g_new0(StatsRequest, 1); + request->provider = provider_idx; + if (names && !g_str_equal(names, "*")) { + request->has_names = true; + request->names = hmp_split_at_comma(names); + } + QAPI_LIST_PREPEND(request_list, request); + } + } + + filter->has_providers = true; + filter->providers = request_list; + return filter; +} + +void hmp_info_stats(Monitor *mon, const QDict *qdict) +{ + const char *target_str = qdict_get_str(qdict, "target"); + const char *provider_str = qdict_get_try_str(qdict, "provider"); + const char *names = qdict_get_try_str(qdict, "names"); + + StatsProvider provider = STATS_PROVIDER__MAX; + StatsTarget target; + Error *err = NULL; + g_autoptr(StatsSchemaList) schema = NULL; + g_autoptr(StatsResultList) stats = NULL; + g_autoptr(StatsFilter) filter = NULL; + StatsResultList *entry; + + target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err); + if (err) { + monitor_printf(mon, "invalid stats target %s\n", target_str); + goto exit_no_print; + } + if (provider_str) { + provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err); + if (err) { + monitor_printf(mon, "invalid stats provider %s\n", provider_str); + goto exit_no_print; + } + } + + schema = qmp_query_stats_schemas(provider_str ? true : false, + provider, &err); + if (err) { + goto exit; + } + + switch (target) { + case STATS_TARGET_VM: + filter = stats_filter(target, names, -1, provider); + break; + case STATS_TARGET_VCPU: {} + int cpu_index = monitor_get_cpu_index(mon); + filter = stats_filter(target, names, cpu_index, provider); + break; + default: + abort(); + } + + stats = qmp_query_stats(filter, &err); + if (err) { + goto exit; + } + for (entry = stats; entry; entry = entry->next) { + print_stats_results(mon, target, provider_str == NULL, entry->value, schema); + } + +exit: + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + } +exit_no_print: + error_free(err); +} From 5bd26d78d9629a9d3f4780a162f09272978eae3d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:38 +0100 Subject: [PATCH 461/814] acpi: Move the QMP command from monitor/ to hw/acpi/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the command from MAINTAINERS section "QMP" to section "ACPI/SMBIOS)". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-25-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/acpi/acpi-qmp-cmds.c | 30 ++++++++++++++++++++++++++++++ hw/acpi/meson.build | 1 + monitor/qmp-cmds.c | 21 --------------------- 3 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 hw/acpi/acpi-qmp-cmds.c diff --git a/hw/acpi/acpi-qmp-cmds.c b/hw/acpi/acpi-qmp-cmds.c new file mode 100644 index 0000000000..2d47cac52c --- /dev/null +++ b/hw/acpi/acpi-qmp-cmds.c @@ -0,0 +1,30 @@ +/* + * QMP commands related to ACPI + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/acpi_dev_interface.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-acpi.h" + +ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) +{ + bool ambig; + ACPIOSTInfoList *head = NULL; + ACPIOSTInfoList **prev = &head; + Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig); + + if (obj) { + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); + AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); + + adevc->ospm_status(adev, &prev); + } else { + error_setg(errp, "command is not supported, missing ACPI device"); + } + + return head; +} diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 50b73129b4..e0bf39bf4c 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -38,3 +38,4 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub 'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c', 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c', 'cxl-stub.c', 'pci-bridge-stub.c')) +softmmu_ss.add(files('acpi-qmp-cmds.c')) diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index ab23e52f97..cc22f3fcc7 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -22,12 +22,10 @@ #include "sysemu/runstate-action.h" #include "sysemu/block-backend.h" #include "qapi/error.h" -#include "qapi/qapi-commands-acpi.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" #include "qapi/type-helpers.h" #include "hw/mem/memory-device.h" -#include "hw/acpi/acpi_dev_interface.h" #include "hw/intc/intc.h" #include "hw/rdma/rdma.h" @@ -153,22 +151,3 @@ void qmp_add_client(const char *protocol, const char *fdname, close(fd); } } - -ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) -{ - bool ambig; - ACPIOSTInfoList *head = NULL; - ACPIOSTInfoList **prev = &head; - Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig); - - if (obj) { - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); - - adevc->ospm_status(adev, &prev); - } else { - error_setg(errp, "command is not supported, missing ACPI device"); - } - - return head; -} From 9c9c5ce7f7d63e654d21a61c58366a7306bcab9f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:39 +0100 Subject: [PATCH 462/814] qdev: Move HMP command completion from monitor to softmmu/ This moves the completion code from MAINTAINERS sections "Human Monitor (HMP)" and "QMP" to section "QOM". Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-26-armbru@redhat.com> --- monitor/misc.c | 82 ------------------------------------------ softmmu/qdev-monitor.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index a2584df0ca..c76d583b4f 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1206,88 +1206,6 @@ int get_monitor_def(Monitor *mon, int64_t *pval, const char *name) return ret; } -void device_add_completion(ReadLineState *rs, int nb_args, const char *str) -{ - GSList *list, *elt; - size_t len; - - if (nb_args != 2) { - return; - } - - len = strlen(str); - readline_set_completion_index(rs, len); - list = elt = object_class_get_list(TYPE_DEVICE, false); - while (elt) { - DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, - TYPE_DEVICE); - - if (dc->user_creatable) { - readline_add_completion_of(rs, str, - object_class_get_name(OBJECT_CLASS(dc))); - } - elt = elt->next; - } - g_slist_free(list); -} - -static int qdev_add_hotpluggable_device(Object *obj, void *opaque) -{ - GSList **list = opaque; - DeviceState *dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE); - - if (dev == NULL) { - return 0; - } - - if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) { - *list = g_slist_append(*list, dev); - } - - return 0; -} - -static GSList *qdev_build_hotpluggable_device_list(Object *peripheral) -{ - GSList *list = NULL; - - object_child_foreach(peripheral, qdev_add_hotpluggable_device, &list); - - return list; -} - -static void peripheral_device_del_completion(ReadLineState *rs, - const char *str) -{ - Object *peripheral = container_get(qdev_get_machine(), "/peripheral"); - GSList *list, *item; - - list = qdev_build_hotpluggable_device_list(peripheral); - if (!list) { - return; - } - - for (item = list; item; item = g_slist_next(item)) { - DeviceState *dev = item->data; - - if (dev->id) { - readline_add_completion_of(rs, str, dev->id); - } - } - - g_slist_free(list); -} - -void device_del_completion(ReadLineState *rs, int nb_args, const char *str) -{ - if (nb_args != 2) { - return; - } - - readline_set_completion_index(rs, strlen(str)); - peripheral_device_del_completion(rs, str); -} - static int compare_mon_cmd(const void *a, const void *b) { diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 4b0ef65780..b8d2c4dadd 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -973,6 +973,88 @@ void hmp_device_del(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, err); } +void device_add_completion(ReadLineState *rs, int nb_args, const char *str) +{ + GSList *list, *elt; + size_t len; + + if (nb_args != 2) { + return; + } + + len = strlen(str); + readline_set_completion_index(rs, len); + list = elt = object_class_get_list(TYPE_DEVICE, false); + while (elt) { + DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, + TYPE_DEVICE); + + if (dc->user_creatable) { + readline_add_completion_of(rs, str, + object_class_get_name(OBJECT_CLASS(dc))); + } + elt = elt->next; + } + g_slist_free(list); +} + +static int qdev_add_hotpluggable_device(Object *obj, void *opaque) +{ + GSList **list = opaque; + DeviceState *dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE); + + if (dev == NULL) { + return 0; + } + + if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) { + *list = g_slist_append(*list, dev); + } + + return 0; +} + +static GSList *qdev_build_hotpluggable_device_list(Object *peripheral) +{ + GSList *list = NULL; + + object_child_foreach(peripheral, qdev_add_hotpluggable_device, &list); + + return list; +} + +static void peripheral_device_del_completion(ReadLineState *rs, + const char *str) +{ + Object *peripheral = container_get(qdev_get_machine(), "/peripheral"); + GSList *list, *item; + + list = qdev_build_hotpluggable_device_list(peripheral); + if (!list) { + return; + } + + for (item = list; item; item = g_slist_next(item)) { + DeviceState *dev = item->data; + + if (dev->id) { + readline_add_completion_of(rs, str, dev->id); + } + } + + g_slist_free(list); +} + +void device_del_completion(ReadLineState *rs, int nb_args, const char *str) +{ + if (nb_args != 2) { + return; + } + + readline_set_completion_index(rs, strlen(str)); + peripheral_device_del_completion(rs, str); +} + BlockBackend *blk_by_qdev_id(const char *id, Error **errp) { DeviceState *dev; From 7ef88b53343efc932dfecfa01426e179dd042dd4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:40 +0100 Subject: [PATCH 463/814] monitor: Split file descriptor passing stuff off misc.c Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-27-armbru@redhat.com> --- monitor/fds.c | 468 ++++++++++++++++++++++++++++++++++++++++++++ monitor/meson.build | 1 + monitor/misc.c | 434 ---------------------------------------- 3 files changed, 469 insertions(+), 434 deletions(-) create mode 100644 monitor/fds.c diff --git a/monitor/fds.c b/monitor/fds.c new file mode 100644 index 0000000000..26b39a0ce6 --- /dev/null +++ b/monitor/fds.c @@ -0,0 +1,468 @@ +/* + * QEMU monitor file descriptor passing + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "monitor-internal.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qerror.h" +#include "qemu/ctype.h" +#include "qemu/cutils.h" +#include "sysemu/runstate.h" + +/* file descriptors passed via SCM_RIGHTS */ +typedef struct mon_fd_t mon_fd_t; +struct mon_fd_t { + char *name; + int fd; + QLIST_ENTRY(mon_fd_t) next; +}; + +/* file descriptor associated with a file descriptor set */ +typedef struct MonFdsetFd MonFdsetFd; +struct MonFdsetFd { + int fd; + bool removed; + char *opaque; + QLIST_ENTRY(MonFdsetFd) next; +}; + +/* file descriptor set containing fds passed via SCM_RIGHTS */ +typedef struct MonFdset MonFdset; +struct MonFdset { + int64_t id; + QLIST_HEAD(, MonFdsetFd) fds; + QLIST_HEAD(, MonFdsetFd) dup_fds; + QLIST_ENTRY(MonFdset) next; +}; + +/* Protects mon_fdsets */ +static QemuMutex mon_fdsets_lock; +static QLIST_HEAD(, MonFdset) mon_fdsets; + +void qmp_getfd(const char *fdname, Error **errp) +{ + Monitor *cur_mon = monitor_cur(); + mon_fd_t *monfd; + int fd, tmp_fd; + + fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); + if (fd == -1) { + error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); + return; + } + + if (qemu_isdigit(fdname[0])) { + close(fd); + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", + "a name not starting with a digit"); + return; + } + + QEMU_LOCK_GUARD(&cur_mon->mon_lock); + QLIST_FOREACH(monfd, &cur_mon->fds, next) { + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + tmp_fd = monfd->fd; + monfd->fd = fd; + /* Make sure close() is outside critical section */ + close(tmp_fd); + return; + } + + monfd = g_new0(mon_fd_t, 1); + monfd->name = g_strdup(fdname); + monfd->fd = fd; + + QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next); +} + +void qmp_closefd(const char *fdname, Error **errp) +{ + Monitor *cur_mon = monitor_cur(); + mon_fd_t *monfd; + int tmp_fd; + + qemu_mutex_lock(&cur_mon->mon_lock); + QLIST_FOREACH(monfd, &cur_mon->fds, next) { + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + QLIST_REMOVE(monfd, next); + tmp_fd = monfd->fd; + g_free(monfd->name); + g_free(monfd); + qemu_mutex_unlock(&cur_mon->mon_lock); + /* Make sure close() is outside critical section */ + close(tmp_fd); + return; + } + + qemu_mutex_unlock(&cur_mon->mon_lock); + error_setg(errp, "File descriptor named '%s' not found", fdname); +} + +int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) +{ + mon_fd_t *monfd; + + QEMU_LOCK_GUARD(&mon->mon_lock); + QLIST_FOREACH(monfd, &mon->fds, next) { + int fd; + + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + fd = monfd->fd; + assert(fd >= 0); + + /* caller takes ownership of fd */ + QLIST_REMOVE(monfd, next); + g_free(monfd->name); + g_free(monfd); + + return fd; + } + + error_setg(errp, "File descriptor named '%s' has not been found", fdname); + return -1; +} + +static void monitor_fdset_cleanup(MonFdset *mon_fdset) +{ + MonFdsetFd *mon_fdset_fd; + MonFdsetFd *mon_fdset_fd_next; + + QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { + if ((mon_fdset_fd->removed || + (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) && + runstate_is_running()) { + close(mon_fdset_fd->fd); + g_free(mon_fdset_fd->opaque); + QLIST_REMOVE(mon_fdset_fd, next); + g_free(mon_fdset_fd); + } + } + + if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { + QLIST_REMOVE(mon_fdset, next); + g_free(mon_fdset); + } +} + +void monitor_fdsets_cleanup(void) +{ + MonFdset *mon_fdset; + MonFdset *mon_fdset_next; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { + monitor_fdset_cleanup(mon_fdset); + } +} + +AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, + const char *opaque, Error **errp) +{ + int fd; + Monitor *mon = monitor_cur(); + AddfdInfo *fdinfo; + + fd = qemu_chr_fe_get_msgfd(&mon->chr); + if (fd == -1) { + error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); + goto error; + } + + fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); + if (fdinfo) { + return fdinfo; + } + +error: + if (fd != -1) { + close(fd); + } + return NULL; +} + +void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd; + char fd_str[60]; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + if (mon_fdset->id != fdset_id) { + continue; + } + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + if (has_fd) { + if (mon_fdset_fd->fd != fd) { + continue; + } + mon_fdset_fd->removed = true; + break; + } else { + mon_fdset_fd->removed = true; + } + } + if (has_fd && !mon_fdset_fd) { + goto error; + } + monitor_fdset_cleanup(mon_fdset); + return; + } + +error: + if (has_fd) { + snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, + fdset_id, fd); + } else { + snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); + } + error_setg(errp, "File descriptor named '%s' not found", fd_str); +} + +FdsetInfoList *qmp_query_fdsets(Error **errp) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd; + FdsetInfoList *fdset_list = NULL; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info)); + + fdset_info->fdset_id = mon_fdset->id; + + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + FdsetFdInfo *fdsetfd_info; + + fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); + fdsetfd_info->fd = mon_fdset_fd->fd; + fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); + + QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); + } + + QAPI_LIST_PREPEND(fdset_list, fdset_info); + } + + return fdset_list; +} + +AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, + const char *opaque, Error **errp) +{ + MonFdset *mon_fdset = NULL; + MonFdsetFd *mon_fdset_fd; + AddfdInfo *fdinfo; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + if (has_fdset_id) { + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + /* Break if match found or match impossible due to ordering by ID */ + if (fdset_id <= mon_fdset->id) { + if (fdset_id < mon_fdset->id) { + mon_fdset = NULL; + } + break; + } + } + } + + if (mon_fdset == NULL) { + int64_t fdset_id_prev = -1; + MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); + + if (has_fdset_id) { + if (fdset_id < 0) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", + "a non-negative value"); + return NULL; + } + /* Use specified fdset ID */ + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + mon_fdset_cur = mon_fdset; + if (fdset_id < mon_fdset_cur->id) { + break; + } + } + } else { + /* Use first available fdset ID */ + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + mon_fdset_cur = mon_fdset; + if (fdset_id_prev == mon_fdset_cur->id - 1) { + fdset_id_prev = mon_fdset_cur->id; + continue; + } + break; + } + } + + mon_fdset = g_malloc0(sizeof(*mon_fdset)); + if (has_fdset_id) { + mon_fdset->id = fdset_id; + } else { + mon_fdset->id = fdset_id_prev + 1; + } + + /* The fdset list is ordered by fdset ID */ + if (!mon_fdset_cur) { + QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); + } else if (mon_fdset->id < mon_fdset_cur->id) { + QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); + } else { + QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); + } + } + + mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); + mon_fdset_fd->fd = fd; + mon_fdset_fd->removed = false; + mon_fdset_fd->opaque = g_strdup(opaque); + QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); + + fdinfo = g_malloc0(sizeof(*fdinfo)); + fdinfo->fdset_id = mon_fdset->id; + fdinfo->fd = mon_fdset_fd->fd; + + return fdinfo; +} + +int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) +{ +#ifdef _WIN32 + return -ENOENT; +#else + MonFdset *mon_fdset; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + MonFdsetFd *mon_fdset_fd; + MonFdsetFd *mon_fdset_fd_dup; + int fd = -1; + int dup_fd; + int mon_fd_flags; + + if (mon_fdset->id != fdset_id) { + continue; + } + + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); + if (mon_fd_flags == -1) { + return -1; + } + + if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { + fd = mon_fdset_fd->fd; + break; + } + } + + if (fd == -1) { + errno = EACCES; + return -1; + } + + dup_fd = qemu_dup_flags(fd, flags); + if (dup_fd == -1) { + return -1; + } + + mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); + mon_fdset_fd_dup->fd = dup_fd; + QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); + return dup_fd; + } + + errno = ENOENT; + return -1; +#endif +} + +static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd_dup; + + QEMU_LOCK_GUARD(&mon_fdsets_lock); + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { + if (mon_fdset_fd_dup->fd == dup_fd) { + if (remove) { + QLIST_REMOVE(mon_fdset_fd_dup, next); + g_free(mon_fdset_fd_dup); + if (QLIST_EMPTY(&mon_fdset->dup_fds)) { + monitor_fdset_cleanup(mon_fdset); + } + return -1; + } else { + return mon_fdset->id; + } + } + } + } + + return -1; +} + +int64_t monitor_fdset_dup_fd_find(int dup_fd) +{ + return monitor_fdset_dup_fd_find_remove(dup_fd, false); +} + +void monitor_fdset_dup_fd_remove(int dup_fd) +{ + monitor_fdset_dup_fd_find_remove(dup_fd, true); +} + +int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) +{ + int fd; + + if (!qemu_isdigit(fdname[0]) && mon) { + fd = monitor_get_fd(mon, fdname, errp); + } else { + fd = qemu_parse_fd(fdname); + if (fd < 0) { + error_setg(errp, "Invalid file descriptor number '%s'", + fdname); + } + } + + return fd; +} + +static void __attribute__((__constructor__)) monitor_fds_init(void) +{ + qemu_mutex_init(&mon_fdsets_lock); +} diff --git a/monitor/meson.build b/monitor/meson.build index 6d00985ace..435d8abd06 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -1,6 +1,7 @@ qmp_ss.add(files('monitor.c', 'qmp.c', 'qmp-cmds-control.c')) softmmu_ss.add(files( + 'fds.c', 'hmp-cmds.c', 'hmp.c', )) diff --git a/monitor/misc.c b/monitor/misc.c index c76d583b4f..c531d95b5b 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -27,11 +27,9 @@ #include "monitor/qdev.h" #include "exec/gdbstub.h" #include "net/slirp.h" -#include "qemu/ctype.h" #include "disas/disas.h" #include "qemu/log.h" #include "sysemu/hw_accel.h" -#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" @@ -56,36 +54,6 @@ /* Make devices configuration available for use in hmp-commands*.hx templates */ #include CONFIG_DEVICES -/* file descriptors passed via SCM_RIGHTS */ -typedef struct mon_fd_t mon_fd_t; -struct mon_fd_t { - char *name; - int fd; - QLIST_ENTRY(mon_fd_t) next; -}; - -/* file descriptor associated with a file descriptor set */ -typedef struct MonFdsetFd MonFdsetFd; -struct MonFdsetFd { - int fd; - bool removed; - char *opaque; - QLIST_ENTRY(MonFdsetFd) next; -}; - -/* file descriptor set containing fds passed via SCM_RIGHTS */ -typedef struct MonFdset MonFdset; -struct MonFdset { - int64_t id; - QLIST_HEAD(, MonFdsetFd) fds; - QLIST_HEAD(, MonFdsetFd) dup_fds; - QLIST_ENTRY(MonFdset) next; -}; - -/* Protects mon_fdsets */ -static QemuMutex mon_fdsets_lock; -static QLIST_HEAD(, MonFdset) mon_fdsets; - static HMPCommand hmp_info_cmds[]; char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, @@ -746,407 +714,6 @@ static void hmp_info_mtree(Monitor *mon, const QDict *qdict) mtree_info(flatview, dispatch_tree, owner, disabled); } -void qmp_getfd(const char *fdname, Error **errp) -{ - Monitor *cur_mon = monitor_cur(); - mon_fd_t *monfd; - int fd, tmp_fd; - - fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); - if (fd == -1) { - error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); - return; - } - - if (qemu_isdigit(fdname[0])) { - close(fd); - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", - "a name not starting with a digit"); - return; - } - - QEMU_LOCK_GUARD(&cur_mon->mon_lock); - QLIST_FOREACH(monfd, &cur_mon->fds, next) { - if (strcmp(monfd->name, fdname) != 0) { - continue; - } - - tmp_fd = monfd->fd; - monfd->fd = fd; - /* Make sure close() is outside critical section */ - close(tmp_fd); - return; - } - - monfd = g_new0(mon_fd_t, 1); - monfd->name = g_strdup(fdname); - monfd->fd = fd; - - QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next); -} - -void qmp_closefd(const char *fdname, Error **errp) -{ - Monitor *cur_mon = monitor_cur(); - mon_fd_t *monfd; - int tmp_fd; - - qemu_mutex_lock(&cur_mon->mon_lock); - QLIST_FOREACH(monfd, &cur_mon->fds, next) { - if (strcmp(monfd->name, fdname) != 0) { - continue; - } - - QLIST_REMOVE(monfd, next); - tmp_fd = monfd->fd; - g_free(monfd->name); - g_free(monfd); - qemu_mutex_unlock(&cur_mon->mon_lock); - /* Make sure close() is outside critical section */ - close(tmp_fd); - return; - } - - qemu_mutex_unlock(&cur_mon->mon_lock); - error_setg(errp, "File descriptor named '%s' not found", fdname); -} - -int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) -{ - mon_fd_t *monfd; - - QEMU_LOCK_GUARD(&mon->mon_lock); - QLIST_FOREACH(monfd, &mon->fds, next) { - int fd; - - if (strcmp(monfd->name, fdname) != 0) { - continue; - } - - fd = monfd->fd; - assert(fd >= 0); - - /* caller takes ownership of fd */ - QLIST_REMOVE(monfd, next); - g_free(monfd->name); - g_free(monfd); - - return fd; - } - - error_setg(errp, "File descriptor named '%s' has not been found", fdname); - return -1; -} - -static void monitor_fdset_cleanup(MonFdset *mon_fdset) -{ - MonFdsetFd *mon_fdset_fd; - MonFdsetFd *mon_fdset_fd_next; - - QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { - if ((mon_fdset_fd->removed || - (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) && - runstate_is_running()) { - close(mon_fdset_fd->fd); - g_free(mon_fdset_fd->opaque); - QLIST_REMOVE(mon_fdset_fd, next); - g_free(mon_fdset_fd); - } - } - - if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { - QLIST_REMOVE(mon_fdset, next); - g_free(mon_fdset); - } -} - -void monitor_fdsets_cleanup(void) -{ - MonFdset *mon_fdset; - MonFdset *mon_fdset_next; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { - monitor_fdset_cleanup(mon_fdset); - } -} - -AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, - const char *opaque, Error **errp) -{ - int fd; - Monitor *mon = monitor_cur(); - AddfdInfo *fdinfo; - - fd = qemu_chr_fe_get_msgfd(&mon->chr); - if (fd == -1) { - error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); - goto error; - } - - fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); - if (fdinfo) { - return fdinfo; - } - -error: - if (fd != -1) { - close(fd); - } - return NULL; -} - -void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) -{ - MonFdset *mon_fdset; - MonFdsetFd *mon_fdset_fd; - char fd_str[60]; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - if (mon_fdset->id != fdset_id) { - continue; - } - QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { - if (has_fd) { - if (mon_fdset_fd->fd != fd) { - continue; - } - mon_fdset_fd->removed = true; - break; - } else { - mon_fdset_fd->removed = true; - } - } - if (has_fd && !mon_fdset_fd) { - goto error; - } - monitor_fdset_cleanup(mon_fdset); - return; - } - -error: - if (has_fd) { - snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, - fdset_id, fd); - } else { - snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); - } - error_setg(errp, "File descriptor named '%s' not found", fd_str); -} - -FdsetInfoList *qmp_query_fdsets(Error **errp) -{ - MonFdset *mon_fdset; - MonFdsetFd *mon_fdset_fd; - FdsetInfoList *fdset_list = NULL; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info)); - - fdset_info->fdset_id = mon_fdset->id; - - QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { - FdsetFdInfo *fdsetfd_info; - - fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); - fdsetfd_info->fd = mon_fdset_fd->fd; - fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); - - QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); - } - - QAPI_LIST_PREPEND(fdset_list, fdset_info); - } - - return fdset_list; -} - -AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, - const char *opaque, Error **errp) -{ - MonFdset *mon_fdset = NULL; - MonFdsetFd *mon_fdset_fd; - AddfdInfo *fdinfo; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - if (has_fdset_id) { - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - /* Break if match found or match impossible due to ordering by ID */ - if (fdset_id <= mon_fdset->id) { - if (fdset_id < mon_fdset->id) { - mon_fdset = NULL; - } - break; - } - } - } - - if (mon_fdset == NULL) { - int64_t fdset_id_prev = -1; - MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); - - if (has_fdset_id) { - if (fdset_id < 0) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", - "a non-negative value"); - return NULL; - } - /* Use specified fdset ID */ - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - mon_fdset_cur = mon_fdset; - if (fdset_id < mon_fdset_cur->id) { - break; - } - } - } else { - /* Use first available fdset ID */ - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - mon_fdset_cur = mon_fdset; - if (fdset_id_prev == mon_fdset_cur->id - 1) { - fdset_id_prev = mon_fdset_cur->id; - continue; - } - break; - } - } - - mon_fdset = g_malloc0(sizeof(*mon_fdset)); - if (has_fdset_id) { - mon_fdset->id = fdset_id; - } else { - mon_fdset->id = fdset_id_prev + 1; - } - - /* The fdset list is ordered by fdset ID */ - if (!mon_fdset_cur) { - QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); - } else if (mon_fdset->id < mon_fdset_cur->id) { - QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); - } else { - QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); - } - } - - mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); - mon_fdset_fd->fd = fd; - mon_fdset_fd->removed = false; - mon_fdset_fd->opaque = g_strdup(opaque); - QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); - - fdinfo = g_malloc0(sizeof(*fdinfo)); - fdinfo->fdset_id = mon_fdset->id; - fdinfo->fd = mon_fdset_fd->fd; - - return fdinfo; -} - -int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) -{ -#ifdef _WIN32 - return -ENOENT; -#else - MonFdset *mon_fdset; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - MonFdsetFd *mon_fdset_fd; - MonFdsetFd *mon_fdset_fd_dup; - int fd = -1; - int dup_fd; - int mon_fd_flags; - - if (mon_fdset->id != fdset_id) { - continue; - } - - QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { - mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); - if (mon_fd_flags == -1) { - return -1; - } - - if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { - fd = mon_fdset_fd->fd; - break; - } - } - - if (fd == -1) { - errno = EACCES; - return -1; - } - - dup_fd = qemu_dup_flags(fd, flags); - if (dup_fd == -1) { - return -1; - } - - mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); - mon_fdset_fd_dup->fd = dup_fd; - QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); - return dup_fd; - } - - errno = ENOENT; - return -1; -#endif -} - -static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) -{ - MonFdset *mon_fdset; - MonFdsetFd *mon_fdset_fd_dup; - - QEMU_LOCK_GUARD(&mon_fdsets_lock); - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { - if (mon_fdset_fd_dup->fd == dup_fd) { - if (remove) { - QLIST_REMOVE(mon_fdset_fd_dup, next); - g_free(mon_fdset_fd_dup); - if (QLIST_EMPTY(&mon_fdset->dup_fds)) { - monitor_fdset_cleanup(mon_fdset); - } - return -1; - } else { - return mon_fdset->id; - } - } - } - } - - return -1; -} - -int64_t monitor_fdset_dup_fd_find(int dup_fd) -{ - return monitor_fdset_dup_fd_find_remove(dup_fd, false); -} - -void monitor_fdset_dup_fd_remove(int dup_fd) -{ - monitor_fdset_dup_fd_find_remove(dup_fd, true); -} - -int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) -{ - int fd; - - if (!qemu_isdigit(fdname[0]) && mon) { - fd = monitor_get_fd(mon, fdname, errp); - } else { - fd = qemu_parse_fd(fdname); - if (fd < 0) { - error_setg(errp, "Invalid file descriptor number '%s'", - fdname); - } - } - - return fd; -} - /* Please update hmp-commands.hx when adding or changing commands */ static HMPCommand hmp_info_cmds[] = { #include "hmp-commands-info.h" @@ -1260,5 +827,4 @@ void monitor_init_globals(void) monitor_init_globals_core(); monitor_init_qmp_commands(); sortcmdlist(); - qemu_mutex_init(&mon_fdsets_lock); } From dd00d7fa653de2768d036f88b77ea936b8f0571e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:41 +0100 Subject: [PATCH 464/814] monitor: Move monitor_putc() next to monitor_puts & external linkage monitor_putc() will soon be used from more than one .c file. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-28-armbru@redhat.com> --- include/monitor/monitor.h | 1 + monitor/misc.c | 27 --------------------------- monitor/monitor.c | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 1e6f4c9bd7..033390f699 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -35,6 +35,7 @@ int monitor_puts(Monitor *mon, const char *str); int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); int monitor_printf(Monitor *mon, const char *fmt, ...) G_GNUC_PRINTF(2, 3); +void monitor_printc(Monitor *mon, int ch); void monitor_flush(Monitor *mon); int monitor_set_cpu(Monitor *mon, int cpu_index); int monitor_get_cpu_index(Monitor *mon); diff --git a/monitor/misc.c b/monitor/misc.c index c531d95b5b..7a0ba35923 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -304,33 +304,6 @@ static void hmp_gdbserver(Monitor *mon, const QDict *qdict) } } -static void monitor_printc(Monitor *mon, int c) -{ - monitor_printf(mon, "'"); - switch(c) { - case '\'': - monitor_printf(mon, "\\'"); - break; - case '\\': - monitor_printf(mon, "\\\\"); - break; - case '\n': - monitor_printf(mon, "\\n"); - break; - case '\r': - monitor_printf(mon, "\\r"); - break; - default: - if (c >= 32 && c <= 126) { - monitor_printf(mon, "%c", c); - } else { - monitor_printf(mon, "\\x%02x", c); - } - break; - } - monitor_printf(mon, "'"); -} - static void memory_dump(Monitor *mon, int count, int format, int wsize, hwaddr addr, int is_physical) { diff --git a/monitor/monitor.c b/monitor/monitor.c index 7ed7bd5342..e1d5002adf 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -260,6 +260,33 @@ int monitor_printf(Monitor *mon, const char *fmt, ...) return ret; } +void monitor_printc(Monitor *mon, int c) +{ + monitor_printf(mon, "'"); + switch(c) { + case '\'': + monitor_printf(mon, "\\'"); + break; + case '\\': + monitor_printf(mon, "\\\\"); + break; + case '\n': + monitor_printf(mon, "\\n"); + break; + case '\r': + monitor_printf(mon, "\\r"); + break; + default: + if (c >= 32 && c <= 126) { + monitor_printf(mon, "%c", c); + } else { + monitor_printf(mon, "\\x%02x", c); + } + break; + } + monitor_printf(mon, "'"); +} + /* * Print to current monitor if we have one, else to stderr. */ From e22455664b000e60065fb038f1c960b429e4e7db Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:42 +0100 Subject: [PATCH 465/814] monitor: Move target-dependent HMP commands to hmp-cmds-target.c Target-independent hmp_gpa2hva(), hmp_gpa2hpa() move along to stay next to hmp_gva2gpa(). Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-29-armbru@redhat.com> --- include/monitor/hmp-target.h | 6 + monitor/hmp-cmds-target.c | 380 +++++++++++++++++++++++++++++++++++ monitor/meson.build | 3 +- monitor/misc.c | 350 -------------------------------- 4 files changed, 388 insertions(+), 351 deletions(-) create mode 100644 monitor/hmp-cmds-target.c diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h index 1891a19b21..d78e979f05 100644 --- a/include/monitor/hmp-target.h +++ b/include/monitor/hmp-target.h @@ -51,5 +51,11 @@ void hmp_info_local_apic(Monitor *mon, const QDict *qdict); void hmp_info_sev(Monitor *mon, const QDict *qdict); void hmp_info_sgx(Monitor *mon, const QDict *qdict); void hmp_info_via(Monitor *mon, const QDict *qdict); +void hmp_memory_dump(Monitor *mon, const QDict *qdict); +void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict); +void hmp_info_registers(Monitor *mon, const QDict *qdict); +void hmp_gva2gpa(Monitor *mon, const QDict *qdict); +void hmp_gpa2hva(Monitor *mon, const QDict *qdict); +void hmp_gpa2hpa(Monitor *mon, const QDict *qdict); #endif /* MONITOR_HMP_TARGET_H */ diff --git a/monitor/hmp-cmds-target.c b/monitor/hmp-cmds-target.c new file mode 100644 index 0000000000..0d3e84d960 --- /dev/null +++ b/monitor/hmp-cmds-target.c @@ -0,0 +1,380 @@ +/* + * Miscellaneous target-dependent HMP commands + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "disas/disas.h" +#include "exec/address-spaces.h" +#include "monitor/hmp-target.h" +#include "monitor/monitor-internal.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "sysemu/hw_accel.h" + +/* Set the current CPU defined by the user. Callers must hold BQL. */ +int monitor_set_cpu(Monitor *mon, int cpu_index) +{ + CPUState *cpu; + + cpu = qemu_get_cpu(cpu_index); + if (cpu == NULL) { + return -1; + } + g_free(mon->mon_cpu_path); + mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); + return 0; +} + +/* Callers must hold BQL. */ +static CPUState *mon_get_cpu_sync(Monitor *mon, bool synchronize) +{ + CPUState *cpu = NULL; + + if (mon->mon_cpu_path) { + cpu = (CPUState *) object_resolve_path_type(mon->mon_cpu_path, + TYPE_CPU, NULL); + if (!cpu) { + g_free(mon->mon_cpu_path); + mon->mon_cpu_path = NULL; + } + } + if (!mon->mon_cpu_path) { + if (!first_cpu) { + return NULL; + } + monitor_set_cpu(mon, first_cpu->cpu_index); + cpu = first_cpu; + } + assert(cpu != NULL); + if (synchronize) { + cpu_synchronize_state(cpu); + } + return cpu; +} + +CPUState *mon_get_cpu(Monitor *mon) +{ + return mon_get_cpu_sync(mon, true); +} + +CPUArchState *mon_get_cpu_env(Monitor *mon) +{ + CPUState *cs = mon_get_cpu(mon); + + return cs ? cs->env_ptr : NULL; +} + +int monitor_get_cpu_index(Monitor *mon) +{ + CPUState *cs = mon_get_cpu_sync(mon, false); + + return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX; +} + +void hmp_info_registers(Monitor *mon, const QDict *qdict) +{ + bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false); + int vcpu = qdict_get_try_int(qdict, "vcpu", -1); + CPUState *cs; + + if (all_cpus) { + CPU_FOREACH(cs) { + monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); + cpu_dump_state(cs, NULL, CPU_DUMP_FPU); + } + } else { + cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon); + + if (!cs) { + if (vcpu >= 0) { + monitor_printf(mon, "CPU#%d not available\n", vcpu); + } else { + monitor_printf(mon, "No CPU available\n"); + } + return; + } + + monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); + cpu_dump_state(cs, NULL, CPU_DUMP_FPU); + } +} + +static void memory_dump(Monitor *mon, int count, int format, int wsize, + hwaddr addr, int is_physical) +{ + int l, line_size, i, max_digits, len; + uint8_t buf[16]; + uint64_t v; + CPUState *cs = mon_get_cpu(mon); + + if (!cs && (format == 'i' || !is_physical)) { + monitor_printf(mon, "Can not dump without CPU\n"); + return; + } + + if (format == 'i') { + monitor_disas(mon, cs, addr, count, is_physical); + return; + } + + len = wsize * count; + if (wsize == 1) { + line_size = 8; + } else { + line_size = 16; + } + max_digits = 0; + + switch(format) { + case 'o': + max_digits = DIV_ROUND_UP(wsize * 8, 3); + break; + default: + case 'x': + max_digits = (wsize * 8) / 4; + break; + case 'u': + case 'd': + max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33); + break; + case 'c': + wsize = 1; + break; + } + + while (len > 0) { + if (is_physical) { + monitor_printf(mon, HWADDR_FMT_plx ":", addr); + } else { + monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr); + } + l = len; + if (l > line_size) + l = line_size; + if (is_physical) { + AddressSpace *as = cs ? cs->as : &address_space_memory; + MemTxResult r = address_space_read(as, addr, + MEMTXATTRS_UNSPECIFIED, buf, l); + if (r != MEMTX_OK) { + monitor_printf(mon, " Cannot access memory\n"); + break; + } + } else { + if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) { + monitor_printf(mon, " Cannot access memory\n"); + break; + } + } + i = 0; + while (i < l) { + switch(wsize) { + default: + case 1: + v = ldub_p(buf + i); + break; + case 2: + v = lduw_p(buf + i); + break; + case 4: + v = (uint32_t)ldl_p(buf + i); + break; + case 8: + v = ldq_p(buf + i); + break; + } + monitor_printf(mon, " "); + switch(format) { + case 'o': + monitor_printf(mon, "%#*" PRIo64, max_digits, v); + break; + case 'x': + monitor_printf(mon, "0x%0*" PRIx64, max_digits, v); + break; + case 'u': + monitor_printf(mon, "%*" PRIu64, max_digits, v); + break; + case 'd': + monitor_printf(mon, "%*" PRId64, max_digits, v); + break; + case 'c': + monitor_printc(mon, v); + break; + } + i += wsize; + } + monitor_printf(mon, "\n"); + addr += l; + len -= l; + } +} + +void hmp_memory_dump(Monitor *mon, const QDict *qdict) +{ + int count = qdict_get_int(qdict, "count"); + int format = qdict_get_int(qdict, "format"); + int size = qdict_get_int(qdict, "size"); + target_long addr = qdict_get_int(qdict, "addr"); + + memory_dump(mon, count, format, size, addr, 0); +} + +void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict) +{ + int count = qdict_get_int(qdict, "count"); + int format = qdict_get_int(qdict, "format"); + int size = qdict_get_int(qdict, "size"); + hwaddr addr = qdict_get_int(qdict, "addr"); + + memory_dump(mon, count, format, size, addr, 1); +} + +void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) +{ + Int128 gpa_region_size; + MemoryRegionSection mrs = memory_region_find(get_system_memory(), + addr, size); + + if (!mrs.mr) { + error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr); + return NULL; + } + + if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { + error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + gpa_region_size = int128_make64(size); + if (int128_lt(mrs.size, gpa_region_size)) { + error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx + " exceeded.", addr); + memory_region_unref(mrs.mr); + return NULL; + } + + *p_mr = mrs.mr; + return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); +} + +void hmp_gpa2hva(Monitor *mon, const QDict *qdict) +{ + hwaddr addr = qdict_get_int(qdict, "addr"); + Error *local_err = NULL; + MemoryRegion *mr = NULL; + void *ptr; + + ptr = gpa2hva(&mr, addr, 1, &local_err); + if (local_err) { + error_report_err(local_err); + return; + } + + monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx + " (%s) is %p\n", + addr, mr->name, ptr); + + memory_region_unref(mr); +} + +void hmp_gva2gpa(Monitor *mon, const QDict *qdict) +{ + target_ulong addr = qdict_get_int(qdict, "addr"); + MemTxAttrs attrs; + CPUState *cs = mon_get_cpu(mon); + hwaddr gpa; + + if (!cs) { + monitor_printf(mon, "No cpu\n"); + return; + } + + gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs); + if (gpa == -1) { + monitor_printf(mon, "Unmapped\n"); + } else { + monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n", + gpa + (addr & ~TARGET_PAGE_MASK)); + } +} + +#ifdef CONFIG_LINUX +static uint64_t vtop(void *ptr, Error **errp) +{ + uint64_t pinfo; + uint64_t ret = -1; + uintptr_t addr = (uintptr_t) ptr; + uintptr_t pagesize = qemu_real_host_page_size(); + off_t offset = addr / pagesize * sizeof(pinfo); + int fd; + + fd = open("/proc/self/pagemap", O_RDONLY); + if (fd == -1) { + error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap"); + return -1; + } + + /* Force copy-on-write if necessary. */ + qatomic_add((uint8_t *)ptr, 0); + + if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) { + error_setg_errno(errp, errno, "Cannot read pagemap"); + goto out; + } + if ((pinfo & (1ull << 63)) == 0) { + error_setg(errp, "Page not present"); + goto out; + } + ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1)); + +out: + close(fd); + return ret; +} + +void hmp_gpa2hpa(Monitor *mon, const QDict *qdict) +{ + hwaddr addr = qdict_get_int(qdict, "addr"); + Error *local_err = NULL; + MemoryRegion *mr = NULL; + void *ptr; + uint64_t physaddr; + + ptr = gpa2hva(&mr, addr, 1, &local_err); + if (local_err) { + error_report_err(local_err); + return; + } + + physaddr = vtop(ptr, &local_err); + if (local_err) { + error_report_err(local_err); + } else { + monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx + " (%s) is 0x%" PRIx64 "\n", + addr, mr->name, (uint64_t) physaddr); + } + + memory_region_unref(mr); +} +#endif diff --git a/monitor/meson.build b/monitor/meson.build index 435d8abd06..795a271545 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -7,4 +7,5 @@ softmmu_ss.add(files( )) softmmu_ss.add([spice_headers, files('qmp-cmds.c')]) -specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files('misc.c'), spice]) +specific_ss.add(when: 'CONFIG_SOFTMMU', + if_true: [files( 'hmp-cmds-target.c', 'misc.c'), spice]) diff --git a/monitor/misc.c b/monitor/misc.c index 7a0ba35923..6764d4f49f 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -27,9 +27,7 @@ #include "monitor/qdev.h" #include "exec/gdbstub.h" #include "net/slirp.h" -#include "disas/disas.h" #include "qemu/log.h" -#include "sysemu/hw_accel.h" #include "sysemu/sysemu.h" #include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" @@ -137,94 +135,6 @@ static void monitor_init_qmp_commands(void) QCO_ALLOW_PRECONFIG, 0); } -/* Set the current CPU defined by the user. Callers must hold BQL. */ -int monitor_set_cpu(Monitor *mon, int cpu_index) -{ - CPUState *cpu; - - cpu = qemu_get_cpu(cpu_index); - if (cpu == NULL) { - return -1; - } - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); - return 0; -} - -/* Callers must hold BQL. */ -static CPUState *mon_get_cpu_sync(Monitor *mon, bool synchronize) -{ - CPUState *cpu = NULL; - - if (mon->mon_cpu_path) { - cpu = (CPUState *) object_resolve_path_type(mon->mon_cpu_path, - TYPE_CPU, NULL); - if (!cpu) { - g_free(mon->mon_cpu_path); - mon->mon_cpu_path = NULL; - } - } - if (!mon->mon_cpu_path) { - if (!first_cpu) { - return NULL; - } - monitor_set_cpu(mon, first_cpu->cpu_index); - cpu = first_cpu; - } - assert(cpu != NULL); - if (synchronize) { - cpu_synchronize_state(cpu); - } - return cpu; -} - -CPUState *mon_get_cpu(Monitor *mon) -{ - return mon_get_cpu_sync(mon, true); -} - -CPUArchState *mon_get_cpu_env(Monitor *mon) -{ - CPUState *cs = mon_get_cpu(mon); - - return cs ? cs->env_ptr : NULL; -} - -int monitor_get_cpu_index(Monitor *mon) -{ - CPUState *cs = mon_get_cpu_sync(mon, false); - - return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX; -} - -static void hmp_info_registers(Monitor *mon, const QDict *qdict) -{ - bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false); - int vcpu = qdict_get_try_int(qdict, "vcpu", -1); - CPUState *cs; - - if (all_cpus) { - CPU_FOREACH(cs) { - monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); - cpu_dump_state(cs, NULL, CPU_DUMP_FPU); - } - } else { - cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon); - - if (!cs) { - if (vcpu >= 0) { - monitor_printf(mon, "CPU#%d not available\n", vcpu); - } else { - monitor_printf(mon, "No CPU available\n"); - } - return; - } - - monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index); - cpu_dump_state(cs, NULL, CPU_DUMP_FPU); - } -} - static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) { int64_t max = qdict_get_try_int(qdict, "max", 10); @@ -304,266 +214,6 @@ static void hmp_gdbserver(Monitor *mon, const QDict *qdict) } } -static void memory_dump(Monitor *mon, int count, int format, int wsize, - hwaddr addr, int is_physical) -{ - int l, line_size, i, max_digits, len; - uint8_t buf[16]; - uint64_t v; - CPUState *cs = mon_get_cpu(mon); - - if (!cs && (format == 'i' || !is_physical)) { - monitor_printf(mon, "Can not dump without CPU\n"); - return; - } - - if (format == 'i') { - monitor_disas(mon, cs, addr, count, is_physical); - return; - } - - len = wsize * count; - if (wsize == 1) { - line_size = 8; - } else { - line_size = 16; - } - max_digits = 0; - - switch(format) { - case 'o': - max_digits = DIV_ROUND_UP(wsize * 8, 3); - break; - default: - case 'x': - max_digits = (wsize * 8) / 4; - break; - case 'u': - case 'd': - max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33); - break; - case 'c': - wsize = 1; - break; - } - - while (len > 0) { - if (is_physical) { - monitor_printf(mon, HWADDR_FMT_plx ":", addr); - } else { - monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr); - } - l = len; - if (l > line_size) - l = line_size; - if (is_physical) { - AddressSpace *as = cs ? cs->as : &address_space_memory; - MemTxResult r = address_space_read(as, addr, - MEMTXATTRS_UNSPECIFIED, buf, l); - if (r != MEMTX_OK) { - monitor_printf(mon, " Cannot access memory\n"); - break; - } - } else { - if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) { - monitor_printf(mon, " Cannot access memory\n"); - break; - } - } - i = 0; - while (i < l) { - switch(wsize) { - default: - case 1: - v = ldub_p(buf + i); - break; - case 2: - v = lduw_p(buf + i); - break; - case 4: - v = (uint32_t)ldl_p(buf + i); - break; - case 8: - v = ldq_p(buf + i); - break; - } - monitor_printf(mon, " "); - switch(format) { - case 'o': - monitor_printf(mon, "%#*" PRIo64, max_digits, v); - break; - case 'x': - monitor_printf(mon, "0x%0*" PRIx64, max_digits, v); - break; - case 'u': - monitor_printf(mon, "%*" PRIu64, max_digits, v); - break; - case 'd': - monitor_printf(mon, "%*" PRId64, max_digits, v); - break; - case 'c': - monitor_printc(mon, v); - break; - } - i += wsize; - } - monitor_printf(mon, "\n"); - addr += l; - len -= l; - } -} - -static void hmp_memory_dump(Monitor *mon, const QDict *qdict) -{ - int count = qdict_get_int(qdict, "count"); - int format = qdict_get_int(qdict, "format"); - int size = qdict_get_int(qdict, "size"); - target_long addr = qdict_get_int(qdict, "addr"); - - memory_dump(mon, count, format, size, addr, 0); -} - -static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict) -{ - int count = qdict_get_int(qdict, "count"); - int format = qdict_get_int(qdict, "format"); - int size = qdict_get_int(qdict, "size"); - hwaddr addr = qdict_get_int(qdict, "addr"); - - memory_dump(mon, count, format, size, addr, 1); -} - -void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp) -{ - Int128 gpa_region_size; - MemoryRegionSection mrs = memory_region_find(get_system_memory(), - addr, size); - - if (!mrs.mr) { - error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr); - return NULL; - } - - if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) { - error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - gpa_region_size = int128_make64(size); - if (int128_lt(mrs.size, gpa_region_size)) { - error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx - " exceeded.", addr); - memory_region_unref(mrs.mr); - return NULL; - } - - *p_mr = mrs.mr; - return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region); -} - -static void hmp_gpa2hva(Monitor *mon, const QDict *qdict) -{ - hwaddr addr = qdict_get_int(qdict, "addr"); - Error *local_err = NULL; - MemoryRegion *mr = NULL; - void *ptr; - - ptr = gpa2hva(&mr, addr, 1, &local_err); - if (local_err) { - error_report_err(local_err); - return; - } - - monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx - " (%s) is %p\n", - addr, mr->name, ptr); - - memory_region_unref(mr); -} - -static void hmp_gva2gpa(Monitor *mon, const QDict *qdict) -{ - target_ulong addr = qdict_get_int(qdict, "addr"); - MemTxAttrs attrs; - CPUState *cs = mon_get_cpu(mon); - hwaddr gpa; - - if (!cs) { - monitor_printf(mon, "No cpu\n"); - return; - } - - gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs); - if (gpa == -1) { - monitor_printf(mon, "Unmapped\n"); - } else { - monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n", - gpa + (addr & ~TARGET_PAGE_MASK)); - } -} - -#ifdef CONFIG_LINUX -static uint64_t vtop(void *ptr, Error **errp) -{ - uint64_t pinfo; - uint64_t ret = -1; - uintptr_t addr = (uintptr_t) ptr; - uintptr_t pagesize = qemu_real_host_page_size(); - off_t offset = addr / pagesize * sizeof(pinfo); - int fd; - - fd = open("/proc/self/pagemap", O_RDONLY); - if (fd == -1) { - error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap"); - return -1; - } - - /* Force copy-on-write if necessary. */ - qatomic_add((uint8_t *)ptr, 0); - - if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) { - error_setg_errno(errp, errno, "Cannot read pagemap"); - goto out; - } - if ((pinfo & (1ull << 63)) == 0) { - error_setg(errp, "Page not present"); - goto out; - } - ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1)); - -out: - close(fd); - return ret; -} - -static void hmp_gpa2hpa(Monitor *mon, const QDict *qdict) -{ - hwaddr addr = qdict_get_int(qdict, "addr"); - Error *local_err = NULL; - MemoryRegion *mr = NULL; - void *ptr; - uint64_t physaddr; - - ptr = gpa2hva(&mr, addr, 1, &local_err); - if (local_err) { - error_report_err(local_err); - return; - } - - physaddr = vtop(ptr, &local_err); - if (local_err) { - error_report_err(local_err); - } else { - monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx - " (%s) is 0x%" PRIx64 "\n", - addr, mr->name, (uint64_t) physaddr); - } - - memory_region_unref(mr); -} -#endif - static void do_print(Monitor *mon, const QDict *qdict) { int format = qdict_get_int(qdict, "format"); From cbf819979bcb7ea15a0921a9dc31eded68dda81d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:43 +0100 Subject: [PATCH 466/814] monitor: Move remaining HMP commands from misc.c to hmp-cmds.c This requires giving them external linkage. Rename do_help_cmd() to hmp_help(), and do_print() to hmp_print(). Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-30-armbru@redhat.com> --- hmp-commands.hx | 4 +- include/monitor/hmp.h | 13 +++ monitor/hmp-cmds.c | 219 +++++++++++++++++++++++++++++++++++++++++- monitor/misc.c | 218 ----------------------------------------- 4 files changed, 233 insertions(+), 221 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 673e39a697..fbb5daf09b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -11,7 +11,7 @@ HXCOMM HXCOMM can be used for comments, discarded from both rST and C. .args_type = "name:S?", .params = "[cmd]", .help = "show the help", - .cmd = do_help_cmd, + .cmd = hmp_help, .flags = "p", }, @@ -563,7 +563,7 @@ ERST .args_type = "fmt:/,val:l", .params = "/fmt expr", .help = "print expression value (use $reg for CPU register access)", - .cmd = do_print, + .cmd = hmp_print, }, SRST diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 941da9fde6..2220f14fc9 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -165,5 +165,18 @@ void hmp_wavcapture(Monitor *mon, const QDict *qdict); void hmp_trace_event(Monitor *mon, const QDict *qdict); void hmp_trace_file(Monitor *mon, const QDict *qdict); void hmp_info_trace_events(Monitor *mon, const QDict *qdict); +void hmp_help(Monitor *mon, const QDict *qdict); +void hmp_info_help(Monitor *mon, const QDict *qdict); +void hmp_info_sync_profile(Monitor *mon, const QDict *qdict); +void hmp_info_history(Monitor *mon, const QDict *qdict); +void hmp_logfile(Monitor *mon, const QDict *qdict); +void hmp_log(Monitor *mon, const QDict *qdict); +void hmp_gdbserver(Monitor *mon, const QDict *qdict); +void hmp_print(Monitor *mon, const QDict *qdict); +void hmp_sum(Monitor *mon, const QDict *qdict); +void hmp_ioport_read(Monitor *mon, const QDict *qdict); +void hmp_ioport_write(Monitor *mon, const QDict *qdict); +void hmp_boot_set(Monitor *mon, const QDict *qdict); +void hmp_info_mtree(Monitor *mon, const QDict *qdict); #endif diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 8a3d56bcde..34bd8c67d7 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -14,9 +14,12 @@ */ #include "qemu/osdep.h" +#include "exec/address-spaces.h" +#include "exec/gdbstub.h" +#include "exec/ioport.h" #include "monitor/hmp.h" #include "qemu/help_option.h" -#include "monitor/monitor.h" +#include "monitor/monitor-internal.h" #include "qapi/error.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" @@ -24,6 +27,8 @@ #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" #include "hw/intc/intc.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" bool hmp_handle_error(Monitor *mon, Error *err) { @@ -224,3 +229,215 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict) qapi_free_IOThreadInfoList(info_list); } + +void hmp_help(Monitor *mon, const QDict *qdict) +{ + hmp_help_cmd(mon, qdict_get_try_str(qdict, "name")); +} + +void hmp_info_help(Monitor *mon, const QDict *qdict) +{ + hmp_help_cmd(mon, "info"); +} + +void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) +{ + int64_t max = qdict_get_try_int(qdict, "max", 10); + bool mean = qdict_get_try_bool(qdict, "mean", false); + bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false); + enum QSPSortBy sort_by; + + sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME; + qsp_report(max, sort_by, coalesce); +} + +void hmp_info_history(Monitor *mon, const QDict *qdict) +{ + MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); + int i; + const char *str; + + if (!hmp_mon->rs) { + return; + } + i = 0; + for(;;) { + str = readline_get_history(hmp_mon->rs, i); + if (!str) { + break; + } + monitor_printf(mon, "%d: '%s'\n", i, str); + i++; + } +} + +void hmp_logfile(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + if (!qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err)) { + error_report_err(err); + } +} + +void hmp_log(Monitor *mon, const QDict *qdict) +{ + int mask; + const char *items = qdict_get_str(qdict, "items"); + Error *err = NULL; + + if (!strcmp(items, "none")) { + mask = 0; + } else { + mask = qemu_str_to_log_mask(items); + if (!mask) { + hmp_help_cmd(mon, "log"); + return; + } + } + + if (!qemu_set_log(mask, &err)) { + error_report_err(err); + } +} + +void hmp_gdbserver(Monitor *mon, const QDict *qdict) +{ + const char *device = qdict_get_try_str(qdict, "device"); + if (!device) { + device = "tcp::" DEFAULT_GDBSTUB_PORT; + } + + if (gdbserver_start(device) < 0) { + monitor_printf(mon, "Could not open gdbserver on device '%s'\n", + device); + } else if (strcmp(device, "none") == 0) { + monitor_printf(mon, "Disabled gdbserver\n"); + } else { + monitor_printf(mon, "Waiting for gdb connection on device '%s'\n", + device); + } +} + +void hmp_print(Monitor *mon, const QDict *qdict) +{ + int format = qdict_get_int(qdict, "format"); + hwaddr val = qdict_get_int(qdict, "val"); + + switch(format) { + case 'o': + monitor_printf(mon, "%#" HWADDR_PRIo, val); + break; + case 'x': + monitor_printf(mon, "%#" HWADDR_PRIx, val); + break; + case 'u': + monitor_printf(mon, "%" HWADDR_PRIu, val); + break; + default: + case 'd': + monitor_printf(mon, "%" HWADDR_PRId, val); + break; + case 'c': + monitor_printc(mon, val); + break; + } + monitor_printf(mon, "\n"); +} + +void hmp_sum(Monitor *mon, const QDict *qdict) +{ + uint32_t addr; + uint16_t sum; + uint32_t start = qdict_get_int(qdict, "start"); + uint32_t size = qdict_get_int(qdict, "size"); + + sum = 0; + for(addr = start; addr < (start + size); addr++) { + uint8_t val = address_space_ldub(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + /* BSD sum algorithm ('sum' Unix command) */ + sum = (sum >> 1) | (sum << 15); + sum += val; + } + monitor_printf(mon, "%05d\n", sum); +} + +void hmp_ioport_read(Monitor *mon, const QDict *qdict) +{ + int size = qdict_get_int(qdict, "size"); + int addr = qdict_get_int(qdict, "addr"); + int has_index = qdict_haskey(qdict, "index"); + uint32_t val; + int suffix; + + if (has_index) { + int index = qdict_get_int(qdict, "index"); + cpu_outb(addr & IOPORTS_MASK, index & 0xff); + addr++; + } + addr &= 0xffff; + + switch(size) { + default: + case 1: + val = cpu_inb(addr); + suffix = 'b'; + break; + case 2: + val = cpu_inw(addr); + suffix = 'w'; + break; + case 4: + val = cpu_inl(addr); + suffix = 'l'; + break; + } + monitor_printf(mon, "port%c[0x%04x] = 0x%0*x\n", + suffix, addr, size * 2, val); +} + +void hmp_ioport_write(Monitor *mon, const QDict *qdict) +{ + int size = qdict_get_int(qdict, "size"); + int addr = qdict_get_int(qdict, "addr"); + int val = qdict_get_int(qdict, "val"); + + addr &= IOPORTS_MASK; + + switch (size) { + default: + case 1: + cpu_outb(addr, val); + break; + case 2: + cpu_outw(addr, val); + break; + case 4: + cpu_outl(addr, val); + break; + } +} + +void hmp_boot_set(Monitor *mon, const QDict *qdict) +{ + Error *local_err = NULL; + const char *bootdevice = qdict_get_str(qdict, "bootdevice"); + + qemu_boot_set(bootdevice, &local_err); + if (local_err) { + error_report_err(local_err); + } else { + monitor_printf(mon, "boot device list now set to %s\n", bootdevice); + } +} + +void hmp_info_mtree(Monitor *mon, const QDict *qdict) +{ + bool flatview = qdict_get_try_bool(qdict, "flatview", false); + bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false); + bool owner = qdict_get_try_bool(qdict, "owner", false); + bool disabled = qdict_get_try_bool(qdict, "disabled", false); + + mtree_info(flatview, dispatch_tree, owner, disabled); +} diff --git a/monitor/misc.c b/monitor/misc.c index 6764d4f49f..52a7d7686e 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -25,17 +25,11 @@ #include "qemu/osdep.h" #include "monitor-internal.h" #include "monitor/qdev.h" -#include "exec/gdbstub.h" #include "net/slirp.h" -#include "qemu/log.h" -#include "sysemu/sysemu.h" #include "sysemu/device_tree.h" -#include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "monitor/hmp-target.h" #include "monitor/hmp.h" -#include "exec/address-spaces.h" -#include "exec/ioport.h" #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" @@ -105,16 +99,6 @@ int hmp_compare_cmd(const char *name, const char *list) return 0; } -static void do_help_cmd(Monitor *mon, const QDict *qdict) -{ - hmp_help_cmd(mon, qdict_get_try_str(qdict, "name")); -} - -static void hmp_info_help(Monitor *mon, const QDict *qdict) -{ - hmp_help_cmd(mon, "info"); -} - static void monitor_init_qmp_commands(void) { /* @@ -135,208 +119,6 @@ static void monitor_init_qmp_commands(void) QCO_ALLOW_PRECONFIG, 0); } -static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) -{ - int64_t max = qdict_get_try_int(qdict, "max", 10); - bool mean = qdict_get_try_bool(qdict, "mean", false); - bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false); - enum QSPSortBy sort_by; - - sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME; - qsp_report(max, sort_by, coalesce); -} - -static void hmp_info_history(Monitor *mon, const QDict *qdict) -{ - MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); - int i; - const char *str; - - if (!hmp_mon->rs) { - return; - } - i = 0; - for(;;) { - str = readline_get_history(hmp_mon->rs, i); - if (!str) { - break; - } - monitor_printf(mon, "%d: '%s'\n", i, str); - i++; - } -} - -static void hmp_logfile(Monitor *mon, const QDict *qdict) -{ - Error *err = NULL; - - if (!qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err)) { - error_report_err(err); - } -} - -static void hmp_log(Monitor *mon, const QDict *qdict) -{ - int mask; - const char *items = qdict_get_str(qdict, "items"); - Error *err = NULL; - - if (!strcmp(items, "none")) { - mask = 0; - } else { - mask = qemu_str_to_log_mask(items); - if (!mask) { - hmp_help_cmd(mon, "log"); - return; - } - } - - if (!qemu_set_log(mask, &err)) { - error_report_err(err); - } -} - -static void hmp_gdbserver(Monitor *mon, const QDict *qdict) -{ - const char *device = qdict_get_try_str(qdict, "device"); - if (!device) { - device = "tcp::" DEFAULT_GDBSTUB_PORT; - } - - if (gdbserver_start(device) < 0) { - monitor_printf(mon, "Could not open gdbserver on device '%s'\n", - device); - } else if (strcmp(device, "none") == 0) { - monitor_printf(mon, "Disabled gdbserver\n"); - } else { - monitor_printf(mon, "Waiting for gdb connection on device '%s'\n", - device); - } -} - -static void do_print(Monitor *mon, const QDict *qdict) -{ - int format = qdict_get_int(qdict, "format"); - hwaddr val = qdict_get_int(qdict, "val"); - - switch(format) { - case 'o': - monitor_printf(mon, "%#" HWADDR_PRIo, val); - break; - case 'x': - monitor_printf(mon, "%#" HWADDR_PRIx, val); - break; - case 'u': - monitor_printf(mon, "%" HWADDR_PRIu, val); - break; - default: - case 'd': - monitor_printf(mon, "%" HWADDR_PRId, val); - break; - case 'c': - monitor_printc(mon, val); - break; - } - monitor_printf(mon, "\n"); -} - -static void hmp_sum(Monitor *mon, const QDict *qdict) -{ - uint32_t addr; - uint16_t sum; - uint32_t start = qdict_get_int(qdict, "start"); - uint32_t size = qdict_get_int(qdict, "size"); - - sum = 0; - for(addr = start; addr < (start + size); addr++) { - uint8_t val = address_space_ldub(&address_space_memory, addr, - MEMTXATTRS_UNSPECIFIED, NULL); - /* BSD sum algorithm ('sum' Unix command) */ - sum = (sum >> 1) | (sum << 15); - sum += val; - } - monitor_printf(mon, "%05d\n", sum); -} - -static void hmp_ioport_read(Monitor *mon, const QDict *qdict) -{ - int size = qdict_get_int(qdict, "size"); - int addr = qdict_get_int(qdict, "addr"); - int has_index = qdict_haskey(qdict, "index"); - uint32_t val; - int suffix; - - if (has_index) { - int index = qdict_get_int(qdict, "index"); - cpu_outb(addr & IOPORTS_MASK, index & 0xff); - addr++; - } - addr &= 0xffff; - - switch(size) { - default: - case 1: - val = cpu_inb(addr); - suffix = 'b'; - break; - case 2: - val = cpu_inw(addr); - suffix = 'w'; - break; - case 4: - val = cpu_inl(addr); - suffix = 'l'; - break; - } - monitor_printf(mon, "port%c[0x%04x] = 0x%0*x\n", - suffix, addr, size * 2, val); -} - -static void hmp_ioport_write(Monitor *mon, const QDict *qdict) -{ - int size = qdict_get_int(qdict, "size"); - int addr = qdict_get_int(qdict, "addr"); - int val = qdict_get_int(qdict, "val"); - - addr &= IOPORTS_MASK; - - switch (size) { - default: - case 1: - cpu_outb(addr, val); - break; - case 2: - cpu_outw(addr, val); - break; - case 4: - cpu_outl(addr, val); - break; - } -} - -static void hmp_boot_set(Monitor *mon, const QDict *qdict) -{ - Error *local_err = NULL; - const char *bootdevice = qdict_get_str(qdict, "bootdevice"); - - qemu_boot_set(bootdevice, &local_err); - if (local_err) { - error_report_err(local_err); - } else { - monitor_printf(mon, "boot device list now set to %s\n", bootdevice); - } -} - -static void hmp_info_mtree(Monitor *mon, const QDict *qdict) -{ - bool flatview = qdict_get_try_bool(qdict, "flatview", false); - bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false); - bool owner = qdict_get_try_bool(qdict, "owner", false); - bool disabled = qdict_get_try_bool(qdict, "disabled", false); - - mtree_info(flatview, dispatch_tree, owner, disabled); -} - /* Please update hmp-commands.hx when adding or changing commands */ static HMPCommand hmp_info_cmds[] = { #include "hmp-commands-info.h" From e6e108d138635b33f0ef48058c7aafa58484556b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:44 +0100 Subject: [PATCH 467/814] monitor: Move remaining QMP stuff from misc.c to qmp-cmds.c Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-31-armbru@redhat.com> --- monitor/misc.c | 51 -------------------------------------------- monitor/qmp-cmds.c | 53 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index 52a7d7686e..9ddf32da97 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -27,14 +27,12 @@ #include "monitor/qdev.h" #include "net/slirp.h" #include "sysemu/device_tree.h" -#include "qapi/qmp/qerror.h" #include "monitor/hmp-target.h" #include "monitor/hmp.h" #include "block/block-hmp-cmds.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-commands-machine.h" -#include "qapi/qapi-init-commands.h" #include "qapi/error.h" #include "qemu/cutils.h" @@ -48,34 +46,6 @@ static HMPCommand hmp_info_cmds[]; -char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, - int64_t cpu_index, Error **errp) -{ - char *output = NULL; - MonitorHMP hmp = {}; - - monitor_data_init(&hmp.common, false, true, false); - - if (has_cpu_index) { - int ret = monitor_set_cpu(&hmp.common, cpu_index); - if (ret < 0) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", - "a CPU number"); - goto out; - } - } - - handle_hmp_command(&hmp, command_line); - - WITH_QEMU_LOCK_GUARD(&hmp.common.mon_lock) { - output = g_strdup(hmp.common.outbuf->str); - } - -out: - monitor_data_destroy(&hmp.common); - return output; -} - /** * Is @name in the '|' separated list of names @list? */ @@ -99,26 +69,6 @@ int hmp_compare_cmd(const char *name, const char *list) return 0; } -static void monitor_init_qmp_commands(void) -{ - /* - * Two command lists: - * - qmp_commands contains all QMP commands - * - qmp_cap_negotiation_commands contains just - * "qmp_capabilities", to enforce capability negotiation - */ - - qmp_init_marshal(&qmp_commands); - - qmp_register_command(&qmp_commands, "device_add", - qmp_device_add, 0, 0); - - QTAILQ_INIT(&qmp_cap_negotiation_commands); - qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities", - qmp_marshal_qmp_capabilities, - QCO_ALLOW_PRECONFIG, 0); -} - /* Please update hmp-commands.hx when adding or changing commands */ static HMPCommand hmp_info_cmds[] = { #include "hmp-commands-info.h" @@ -230,6 +180,5 @@ void monitor_register_hmp_info_hrt(const char *name, void monitor_init_globals(void) { monitor_init_globals_core(); - monitor_init_qmp_commands(); sortcmdlist(); } diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index cc22f3fcc7..859012aef4 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -14,7 +14,8 @@ */ #include "qemu/osdep.h" -#include "monitor/monitor.h" +#include "monitor-internal.h" +#include "monitor/qdev.h" #include "monitor/qmp-helpers.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" @@ -22,8 +23,10 @@ #include "sysemu/runstate-action.h" #include "sysemu/block-backend.h" #include "qapi/error.h" +#include "qapi/qapi-init-commands.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qerror.h" #include "qapi/type-helpers.h" #include "hw/mem/memory-device.h" #include "hw/intc/intc.h" @@ -151,3 +154,51 @@ void qmp_add_client(const char *protocol, const char *fdname, close(fd); } } + +char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, + int64_t cpu_index, Error **errp) +{ + char *output = NULL; + MonitorHMP hmp = {}; + + monitor_data_init(&hmp.common, false, true, false); + + if (has_cpu_index) { + int ret = monitor_set_cpu(&hmp.common, cpu_index); + if (ret < 0) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", + "a CPU number"); + goto out; + } + } + + handle_hmp_command(&hmp, command_line); + + WITH_QEMU_LOCK_GUARD(&hmp.common.mon_lock) { + output = g_strdup(hmp.common.outbuf->str); + } + +out: + monitor_data_destroy(&hmp.common); + return output; +} + +static void __attribute__((__constructor__)) monitor_init_qmp_commands(void) +{ + /* + * Two command lists: + * - qmp_commands contains all QMP commands + * - qmp_cap_negotiation_commands contains just + * "qmp_capabilities", to enforce capability negotiation + */ + + qmp_init_marshal(&qmp_commands); + + qmp_register_command(&qmp_commands, "device_add", + qmp_device_add, 0, 0); + + QTAILQ_INIT(&qmp_cap_negotiation_commands); + qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities", + qmp_marshal_qmp_capabilities, + QCO_ALLOW_PRECONFIG, 0); +} From 9d2b5f2ce4c7913406f7d17aafcf2f71757e49d8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:45 +0100 Subject: [PATCH 468/814] monitor: Loosen coupling between misc.c and monitor.c slightly Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-32-armbru@redhat.com> --- monitor/misc.c | 8 +------- monitor/monitor.c | 2 +- storage-daemon/qemu-storage-daemon.c | 4 ++-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/monitor/misc.c b/monitor/misc.c index 9ddf32da97..99317a8ff4 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -135,7 +135,7 @@ compare_mon_cmd(const void *a, const void *b) ((const HMPCommand *)b)->name); } -static void sortcmdlist(void) +static void __attribute__((__constructor__)) sortcmdlist(void) { qsort(hmp_cmds, ARRAY_SIZE(hmp_cmds) - 1, sizeof(*hmp_cmds), @@ -176,9 +176,3 @@ void monitor_register_hmp_info_hrt(const char *name, } g_assert_not_reached(); } - -void monitor_init_globals(void) -{ - monitor_init_globals_core(); - sortcmdlist(); -} diff --git a/monitor/monitor.c b/monitor/monitor.c index e1d5002adf..8dc96f6af9 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -720,7 +720,7 @@ static void monitor_qapi_event_init(void) qapi_event_throttle_equal); } -void monitor_init_globals_core(void) +void monitor_init_globals(void) { monitor_qapi_event_init(); qemu_mutex_init(&monitor_lock); diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c index da19498c66..0e9354faa6 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -299,7 +299,7 @@ static void process_options(int argc, char *argv[], bool pre_init_pass) case OPTION_DAEMONIZE: if (os_set_daemonize(true) < 0) { /* - * --daemonize is parsed before monitor_init_globals_core(), so + * --daemonize is parsed before monitor_init_globals(), so * error_report() does not work yet */ fprintf(stderr, "--daemonize not supported in this build\n"); @@ -411,7 +411,7 @@ int main(int argc, char *argv[]) qemu_add_opts(&qemu_trace_opts); qcrypto_init(&error_fatal); bdrv_init(); - monitor_init_globals_core(); + monitor_init_globals(); init_qmp_commands(); if (!trace_init_backends()) { From 864a3fa439276148b6d7abcf2d43ee8dbe4c4062 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 24 Jan 2023 13:19:46 +0100 Subject: [PATCH 469/814] monitor: Rename misc.c to hmp-target.c What's left in misc.c is exactly the target-dependent part of the HMP core. Rename accordingly. Signed-off-by: Markus Armbruster Message-Id: <20230124121946.1139465-33-armbru@redhat.com> --- monitor/{misc.c => hmp-target.c} | 2 +- monitor/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename monitor/{misc.c => hmp-target.c} (99%) diff --git a/monitor/misc.c b/monitor/hmp-target.c similarity index 99% rename from monitor/misc.c rename to monitor/hmp-target.c index 99317a8ff4..1eb72ac1bf 100644 --- a/monitor/misc.c +++ b/monitor/hmp-target.c @@ -1,5 +1,5 @@ /* - * QEMU monitor + * QEMU monitor, target-dependent part * * Copyright (c) 2003-2004 Fabrice Bellard * diff --git a/monitor/meson.build b/monitor/meson.build index 795a271545..ccb4d1a8e6 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -8,4 +8,4 @@ softmmu_ss.add(files( softmmu_ss.add([spice_headers, files('qmp-cmds.c')]) specific_ss.add(when: 'CONFIG_SOFTMMU', - if_true: [files( 'hmp-cmds-target.c', 'misc.c'), spice]) + if_true: [files( 'hmp-cmds-target.c', 'hmp-target.c'), spice]) From 99ab4d500af638ba3ebb20e8aa89d72201b70860 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 3 Feb 2023 18:15:10 +0100 Subject: [PATCH 470/814] accel/tcg: Test CPUJumpCache in tb_jmp_cache_clear_page After commit 4e4fa6c12d ("accel/tcg: Complete cpu initialization before registration"), it looks the CPUJumpCache pointer can be NULL. This causes a SIGSEV when running debug-wp-migration kvm unit test. At the first place it should be clarified why this TCG code is called with KVM acceleration. This may hide another bug. Fixes: 4e4fa6c12d ("accel/tcg: Complete cpu initialization before registration") Signed-off-by: Eric Auger Message-Id: <20230203171510.2867451-1-eric.auger@redhat.com> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 4e040a1cb9..04e270742e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -100,9 +100,14 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) { - int i, i0 = tb_jmp_cache_hash_page(page_addr); CPUJumpCache *jc = cpu->tb_jmp_cache; + int i, i0; + if (unlikely(!jc)) { + return; + } + + i0 = tb_jmp_cache_hash_page(page_addr); for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { qatomic_set(&jc->array[i0 + i].tb, NULL); } From e1e646524437072e466313b04a2f8326dd7b8e77 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Feb 2023 12:58:12 -1000 Subject: [PATCH 471/814] tcg: Init temp_subindex in liveness_pass_2 Correctly handle large types while lowering. Fixes: fac87bd2a49b ("tcg: Add temp_subindex to TCGTemp") Signed-off-by: Richard Henderson --- tcg/tcg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tcg/tcg.c b/tcg/tcg.c index fd557d55d3..bc60fd0fe8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3063,6 +3063,7 @@ static bool liveness_pass_2(TCGContext *s) TCGTemp *dts = tcg_temp_alloc(s); dts->type = its->type; dts->base_type = its->base_type; + dts->temp_subindex = its->temp_subindex; dts->kind = TEMP_EBB; its->state_ptr = dts; } else { From ecbea3ec1ce5f4499ef6acbc696ec5d6a1c69165 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 11 Nov 2022 10:49:52 +1000 Subject: [PATCH 472/814] tcg: Define TCG_TYPE_I128 and related helper macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Begin staging in support for TCGv_i128 with Int128. Define the type enumerator, the typedef, and the helper-head.h macros. This cannot yet be used, because you can't allocate temporaries of this new type. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/exec/helper-head.h | 7 +++++++ include/tcg/tcg.h | 17 ++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h index bc6698b19f..b8d1140dc7 100644 --- a/include/exec/helper-head.h +++ b/include/exec/helper-head.h @@ -26,6 +26,7 @@ #define dh_alias_int i32 #define dh_alias_i64 i64 #define dh_alias_s64 i64 +#define dh_alias_i128 i128 #define dh_alias_f16 i32 #define dh_alias_f32 i32 #define dh_alias_f64 i64 @@ -40,6 +41,7 @@ #define dh_ctype_int int #define dh_ctype_i64 uint64_t #define dh_ctype_s64 int64_t +#define dh_ctype_i128 Int128 #define dh_ctype_f16 uint32_t #define dh_ctype_f32 float32 #define dh_ctype_f64 float64 @@ -71,6 +73,7 @@ #define dh_retvar_decl0_noreturn void #define dh_retvar_decl0_i32 TCGv_i32 retval #define dh_retvar_decl0_i64 TCGv_i64 retval +#define dh_retval_decl0_i128 TCGv_i128 retval #define dh_retvar_decl0_ptr TCGv_ptr retval #define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t)) @@ -78,6 +81,7 @@ #define dh_retvar_decl_noreturn #define dh_retvar_decl_i32 TCGv_i32 retval, #define dh_retvar_decl_i64 TCGv_i64 retval, +#define dh_retvar_decl_i128 TCGv_i128 retval, #define dh_retvar_decl_ptr TCGv_ptr retval, #define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t)) @@ -85,6 +89,7 @@ #define dh_retvar_noreturn NULL #define dh_retvar_i32 tcgv_i32_temp(retval) #define dh_retvar_i64 tcgv_i64_temp(retval) +#define dh_retvar_i128 tcgv_i128_temp(retval) #define dh_retvar_ptr tcgv_ptr_temp(retval) #define dh_retvar(t) glue(dh_retvar_, dh_alias(t)) @@ -95,6 +100,7 @@ #define dh_typecode_i64 4 #define dh_typecode_s64 5 #define dh_typecode_ptr 6 +#define dh_typecode_i128 7 #define dh_typecode_int dh_typecode_s32 #define dh_typecode_f16 dh_typecode_i32 #define dh_typecode_f32 dh_typecode_i32 @@ -104,6 +110,7 @@ #define dh_callflag_i32 0 #define dh_callflag_i64 0 +#define dh_callflag_i128 0 #define dh_callflag_ptr 0 #define dh_callflag_void 0 #define dh_callflag_noreturn TCG_CALL_NO_RETURN diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c5112da0ef..4d7e4107a9 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -270,6 +270,7 @@ typedef struct TCGPool { typedef enum TCGType { TCG_TYPE_I32, TCG_TYPE_I64, + TCG_TYPE_I128, TCG_TYPE_V64, TCG_TYPE_V128, @@ -351,13 +352,14 @@ typedef tcg_target_ulong TCGArg; in tcg/README. Target CPU front-end code uses these types to deal with TCG variables as it emits TCG code via the tcg_gen_* functions. They come in several flavours: - * TCGv_i32 : 32 bit integer type - * TCGv_i64 : 64 bit integer type - * TCGv_ptr : a host 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 - (an alias for either TCGv_i32 or TCGv_i64) + * TCGv_i32 : 32 bit integer type + * TCGv_i64 : 64 bit integer type + * TCGv_i128 : 128 bit integer type + * TCGv_ptr : a host 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 + (an alias for either TCGv_i32 or TCGv_i64) The compiler's type checking will complain if you mix them up and pass the wrong sized TCGv to a function. @@ -377,6 +379,7 @@ typedef tcg_target_ulong TCGArg; typedef struct TCGv_i32_d *TCGv_i32; typedef struct TCGv_i64_d *TCGv_i64; +typedef struct TCGv_i128_d *TCGv_i128; typedef struct TCGv_ptr_d *TCGv_ptr; typedef struct TCGv_vec_d *TCGv_vec; typedef TCGv_ptr TCGv_env; From 466d37596010845eb61fbb8b5cd7daa407286342 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 11 Nov 2022 11:01:13 +1000 Subject: [PATCH 473/814] tcg: Handle dh_typecode_i128 with TCG_CALL_{RET,ARG}_NORMAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many hosts pass and return 128-bit quantities like sequential 64-bit quantities. Treat this just like we currently break down 64-bit quantities for a 32-bit host. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index bc60fd0fe8..bc7198e5d0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -707,11 +707,22 @@ static void init_call_layout(TCGHelperInfo *info) case dh_typecode_s64: info->nr_out = 64 / TCG_TARGET_REG_BITS; info->out_kind = TCG_CALL_RET_NORMAL; + assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); + break; + case dh_typecode_i128: + info->nr_out = 128 / TCG_TARGET_REG_BITS; + info->out_kind = TCG_CALL_RET_NORMAL; /* TODO */ + switch (/* TODO */ TCG_CALL_RET_NORMAL) { + case TCG_CALL_RET_NORMAL: + assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); + break; + default: + qemu_build_not_reached(); + } break; default: g_assert_not_reached(); } - assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); /* * Parse and place function arguments. @@ -733,6 +744,9 @@ static void init_call_layout(TCGHelperInfo *info) case dh_typecode_ptr: type = TCG_TYPE_PTR; break; + case dh_typecode_i128: + type = TCG_TYPE_I128; + break; default: g_assert_not_reached(); } @@ -772,6 +786,19 @@ static void init_call_layout(TCGHelperInfo *info) } break; + case TCG_TYPE_I128: + switch (/* TODO */ TCG_CALL_ARG_NORMAL) { + case TCG_CALL_ARG_EVEN: + layout_arg_even(&cum); + /* fall through */ + case TCG_CALL_ARG_NORMAL: + layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); + break; + default: + qemu_build_not_reached(); + } + break; + default: g_assert_not_reached(); } @@ -1692,11 +1719,13 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) op->args[pi++] = temp_arg(ret); break; case 2: + case 4: tcg_debug_assert(ret != NULL); - tcg_debug_assert(ret->base_type == ret->type + 1); + tcg_debug_assert(ret->base_type == ret->type + ctz32(n)); tcg_debug_assert(ret->temp_subindex == 0); - op->args[pi++] = temp_arg(ret); - op->args[pi++] = temp_arg(ret + 1); + for (i = 0; i < n; ++i) { + op->args[pi++] = temp_arg(ret + i); + } break; default: g_assert_not_reached(); From 273eb50c0fed6696d4600d9cf26f1b2dfcccab0c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Oct 2022 12:03:40 +1000 Subject: [PATCH 474/814] tcg: Allocate objects contiguously in temp_allocate_frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When allocating a temp to the stack frame, consider the base type and allocate all parts at once. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index bc7198e5d0..cdfc50b164 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3267,11 +3267,12 @@ static bool liveness_pass_2(TCGContext *s) static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) { - int size = tcg_type_size(ts->type); - int align; intptr_t off; + int size, align; - switch (ts->type) { + /* When allocating an object, look at the full type. */ + size = tcg_type_size(ts->base_type); + switch (ts->base_type) { case TCG_TYPE_I32: align = 4; break; @@ -3302,13 +3303,30 @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) tcg_raise_tb_overflow(s); } s->current_frame_offset = off + size; - - ts->mem_offset = off; #if defined(__sparc__) - ts->mem_offset += TCG_TARGET_STACK_BIAS; + off += TCG_TARGET_STACK_BIAS; #endif - ts->mem_base = s->frame_temp; - ts->mem_allocated = 1; + + /* If the object was subdivided, assign memory to all the parts. */ + if (ts->base_type != ts->type) { + int part_size = tcg_type_size(ts->type); + int part_count = size / part_size; + + /* + * Each part is allocated sequentially in tcg_temp_new_internal. + * Jump back to the first part by subtracting the current index. + */ + ts -= ts->temp_subindex; + for (int i = 0; i < part_count; ++i) { + ts[i].mem_offset = off + i * part_size; + ts[i].mem_base = s->frame_temp; + ts[i].mem_allocated = 1; + } + } else { + ts->mem_offset = off; + ts->mem_base = s->frame_temp; + ts->mem_allocated = 1; + } } /* Assign @reg to @ts, and update reg_to_temp[]. */ From 6a6d772e30d62e209587ef341df243e9789f5a9f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Oct 2022 21:28:04 +1000 Subject: [PATCH 475/814] tcg: Introduce tcg_out_addi_ptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the function for arm, i386, and s390x, which will use it. Add stubs for all other backends. Reviewed-by: Alex Bennée Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 7 +++++++ tcg/arm/tcg-target.c.inc | 20 ++++++++++++++++++++ tcg/i386/tcg-target.c.inc | 8 ++++++++ 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 | 2 ++ tcg/tci/tcg-target.c.inc | 7 +++++++ 11 files changed, 86 insertions(+) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 330d26b395..bd6da72678 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1102,6 +1102,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_out_insn(s, 3305, LDR, 0, rd); } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + /* Define something more legible for general use. */ #define tcg_out_ldst_r tcg_out_insn_3310 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0f5f9f4925..6e9e9b9b3f 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2581,6 +2581,26 @@ static void tcg_out_movi(TCGContext *s, TCGType type, tcg_out_movi32(s, COND_AL, ret, arg); } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + int enc, opc = ARITH_ADD; + + /* All of the easiest immediates to encode are positive. */ + if (imm < 0) { + imm = -imm; + opc = ARITH_SUB; + } + enc = encode_imm(imm); + if (enc >= 0) { + tcg_out_dat_imm(s, COND_AL, opc, rd, rs, enc); + } else { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, imm); + tcg_out_dat_reg(s, COND_AL, opc, rd, rs, + TCG_REG_TMP, SHIFT_IMM_LSL(0)); + } +} + /* Type is always V128, with I64 elements. */ static void tcg_out_dup2_vec(TCGContext *s, TCGReg rd, TCGReg rl, TCGReg rh) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index c71c3e664d..7b573bd287 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1069,6 +1069,14 @@ static void tcg_out_movi(TCGContext *s, TCGType type, } } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + tcg_out_modrm_offset(s, OPC_LEA, rd, rs, imm); +} + static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val) { if (val == (int8_t)val) { diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index ce4a153887..b6e2ff6213 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -417,6 +417,13 @@ static void tcg_out_addi(TCGContext *s, TCGType type, TCGReg rd, } } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) { tcg_out_opc_andi(s, ret, arg, 0xff); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 6e000d8e69..d419c4c1fc 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -550,6 +550,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, } } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + 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 */ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 8d6899cf40..85f84fe59e 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1125,6 +1125,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, } } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + static bool mask_operand(uint32_t c, int *mb, int *me) { uint32_t lsb, test; diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 01cb67ef7b..383331025a 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -559,6 +559,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_out_opc_imm(s, OPC_LD, rd, rd, 0); } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) { tcg_out_opc_imm(s, OPC_ANDI, ret, arg, 0xff); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 218318feb2..d8fd755ef0 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1073,6 +1073,13 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, return false; } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + tcg_out_mem(s, RX_LA, RXY_LAY, rd, rs, TCG_REG_NONE, imm); +} + static inline void tcg_out_risbg(TCGContext *s, TCGReg dest, TCGReg src, int msb, int lsb, int ofs, int z) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index dd406bc065..4b834f3f1e 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -496,6 +496,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, tcg_out_movi_int(s, type, ret, arg, false, TCG_REG_T2); } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + static void tcg_out_ldst_rr(TCGContext *s, TCGReg data, TCGReg a1, TCGReg a2, int op) { diff --git a/tcg/tcg.c b/tcg/tcg.c index cdfc50b164..8923b52044 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -104,6 +104,8 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, tcg_target_long arg); +static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long) + __attribute__((unused)); 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_op(TCGContext *s, TCGOpcode opc, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index bc452007c6..33551b43dc 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -557,6 +557,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, } } +static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, + tcg_target_long imm) +{ + /* This function is only used for passing structs by reference. */ + g_assert_not_reached(); +} + static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, const TCGHelperInfo *info) { From 313bdea84d2912fdbb139e746bd9346b3d85ebdc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Oct 2022 09:22:59 +1100 Subject: [PATCH 476/814] tcg: Add TCG_CALL_{RET,ARG}_BY_REF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These will be used by some hosts, both 32 and 64-bit, to pass and return i128. Not yet used, because allocation is not yet enabled. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg-internal.h | 3 + tcg/tcg.c | 135 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index 6e50aeba3a..2ec1ea01df 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -36,6 +36,7 @@ */ typedef enum { TCG_CALL_RET_NORMAL, /* by registers */ + TCG_CALL_RET_BY_REF, /* for i128, by reference */ } TCGCallReturnKind; typedef enum { @@ -44,6 +45,8 @@ typedef enum { TCG_CALL_ARG_EXTEND, /* for i32, as a sign/zero-extended i64 */ TCG_CALL_ARG_EXTEND_U, /* ... as a zero-extended i64 */ TCG_CALL_ARG_EXTEND_S, /* ... as a sign-extended i64 */ + TCG_CALL_ARG_BY_REF, /* for i128, by reference, first */ + TCG_CALL_ARG_BY_REF_N, /* ... by reference, subsequent */ } TCGCallArgumentKind; typedef struct TCGCallArgumentLoc { diff --git a/tcg/tcg.c b/tcg/tcg.c index 8923b52044..123cde7000 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -104,8 +104,7 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1, static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg); static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg ret, tcg_target_long arg); -static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long) - __attribute__((unused)); +static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); 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_op(TCGContext *s, TCGOpcode opc, @@ -683,6 +682,38 @@ static void layout_arg_normal_n(TCGCumulativeArgs *cum, cum->arg_slot += n; } +static void layout_arg_by_ref(TCGCumulativeArgs *cum, TCGHelperInfo *info) +{ + TCGCallArgumentLoc *loc = &info->in[cum->info_in_idx]; + int n = 128 / TCG_TARGET_REG_BITS; + + /* The first subindex carries the pointer. */ + layout_arg_1(cum, info, TCG_CALL_ARG_BY_REF); + + /* + * The callee is allowed to clobber memory associated with + * structure pass by-reference. Therefore we must make copies. + * Allocate space from "ref_slot", which will be adjusted to + * follow the parameters on the stack. + */ + loc[0].ref_slot = cum->ref_slot; + + /* + * Subsequent words also go into the reference slot, but + * do not accumulate into the regular arguments. + */ + for (int i = 1; i < n; ++i) { + loc[i] = (TCGCallArgumentLoc){ + .kind = TCG_CALL_ARG_BY_REF_N, + .arg_idx = cum->arg_idx, + .tmp_subindex = i, + .ref_slot = cum->ref_slot + i, + }; + } + cum->info_in_idx += n; + cum->ref_slot += n; +} + static void init_call_layout(TCGHelperInfo *info) { int max_reg_slots = ARRAY_SIZE(tcg_target_call_iarg_regs); @@ -718,6 +749,14 @@ static void init_call_layout(TCGHelperInfo *info) case TCG_CALL_RET_NORMAL: assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); break; + case TCG_CALL_RET_BY_REF: + /* + * Allocate the first argument to the output. + * We don't need to store this anywhere, just make it + * unavailable for use in the input loop below. + */ + cum.arg_slot = 1; + break; default: qemu_build_not_reached(); } @@ -796,6 +835,9 @@ static void init_call_layout(TCGHelperInfo *info) case TCG_CALL_ARG_NORMAL: layout_arg_normal_n(&cum, info, 128 / TCG_TARGET_REG_BITS); break; + case TCG_CALL_ARG_BY_REF: + layout_arg_by_ref(&cum, info); + break; default: qemu_build_not_reached(); } @@ -811,7 +853,39 @@ static void init_call_layout(TCGHelperInfo *info) assert(cum.info_in_idx <= ARRAY_SIZE(info->in)); /* Validate the backend has enough argument space. */ assert(cum.arg_slot <= max_reg_slots + max_stk_slots); - assert(cum.ref_slot <= max_stk_slots); + + /* + * Relocate the "ref_slot" area to the end of the parameters. + * Minimizing this stack offset helps code size for x86, + * which has a signed 8-bit offset encoding. + */ + if (cum.ref_slot != 0) { + int ref_base = 0; + + if (cum.arg_slot > max_reg_slots) { + int align = __alignof(Int128) / sizeof(tcg_target_long); + + ref_base = cum.arg_slot - max_reg_slots; + if (align > 1) { + ref_base = ROUND_UP(ref_base, align); + } + } + assert(ref_base + cum.ref_slot <= max_stk_slots); + + if (ref_base != 0) { + for (int i = cum.info_in_idx - 1; i >= 0; --i) { + TCGCallArgumentLoc *loc = &info->in[i]; + switch (loc->kind) { + case TCG_CALL_ARG_BY_REF: + case TCG_CALL_ARG_BY_REF_N: + loc->ref_slot += ref_base; + break; + default: + break; + } + } + } + } } static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)]; @@ -1740,6 +1814,8 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) switch (loc->kind) { case TCG_CALL_ARG_NORMAL: + case TCG_CALL_ARG_BY_REF: + case TCG_CALL_ARG_BY_REF_N: op->args[pi++] = temp_arg(ts); break; @@ -4411,6 +4487,27 @@ static void load_arg_normal(TCGContext *s, const TCGCallArgumentLoc *l, } } +static void load_arg_ref(TCGContext *s, int arg_slot, TCGReg ref_base, + intptr_t ref_off, TCGRegSet *allocated_regs) +{ + TCGReg reg; + int stk_slot = arg_slot - ARRAY_SIZE(tcg_target_call_iarg_regs); + + if (stk_slot < 0) { + reg = tcg_target_call_iarg_regs[arg_slot]; + tcg_reg_free(s, reg, *allocated_regs); + tcg_out_addi_ptr(s, reg, ref_base, ref_off); + tcg_regset_set_reg(*allocated_regs, reg); + } else { + reg = tcg_reg_alloc(s, tcg_target_available_regs[TCG_TYPE_PTR], + *allocated_regs, 0, false); + tcg_out_addi_ptr(s, reg, ref_base, ref_off); + tcg_out_st(s, TCG_TYPE_PTR, reg, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET + + stk_slot * sizeof(tcg_target_long)); + } +} + static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) { const int nb_oargs = TCGOP_CALLO(op); @@ -4434,6 +4531,16 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) case TCG_CALL_ARG_EXTEND_S: load_arg_normal(s, loc, ts, &allocated_regs); break; + case TCG_CALL_ARG_BY_REF: + load_arg_stk(s, loc->ref_slot, ts, allocated_regs); + load_arg_ref(s, loc->arg_slot, TCG_REG_CALL_STACK, + TCG_TARGET_CALL_STACK_OFFSET + + loc->ref_slot * sizeof(tcg_target_long), + &allocated_regs); + break; + case TCG_CALL_ARG_BY_REF_N: + load_arg_stk(s, loc->ref_slot, ts, allocated_regs); + break; default: g_assert_not_reached(); } @@ -4465,6 +4572,19 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) save_globals(s, allocated_regs); } + /* + * If the ABI passes a pointer to the returned struct as the first + * argument, load that now. Pass a pointer to the output home slot. + */ + if (info->out_kind == TCG_CALL_RET_BY_REF) { + TCGTemp *ts = arg_temp(op->args[0]); + + if (!ts->mem_allocated) { + temp_allocate_frame(s, ts); + } + load_arg_ref(s, 0, ts->mem_base->reg, ts->mem_offset, &allocated_regs); + } + tcg_out_call(s, tcg_call_func(op), info); /* Assign output registers and emit moves if needed. */ @@ -4481,6 +4601,15 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) ts->mem_coherent = 0; } break; + + case TCG_CALL_RET_BY_REF: + /* The callee has performed a write through the reference. */ + for (i = 0; i < nb_oargs; i++) { + TCGTemp *ts = arg_temp(op->args[i]); + ts->val_type = TEMP_VAL_MEM; + } + break; + default: g_assert_not_reached(); } From 5e3d0c199f4edf4ecdf8100464da441c60ce36e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 00:55:36 +1000 Subject: [PATCH 477/814] tcg: Introduce tcg_target_call_oarg_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the flat array tcg_target_call_oarg_regs[] with a function call including the TCGCallReturnKind. Extend the set of registers for ARM to r0-r3 to match the ABI: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#result-return Reviewed-by: Alex Bennée Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 10 +++++++--- tcg/arm/tcg-target.c.inc | 10 +++++++--- tcg/i386/tcg-target.c.inc | 16 ++++++++++------ tcg/loongarch64/tcg-target.c.inc | 10 ++++++---- tcg/mips/tcg-target.c.inc | 10 ++++++---- tcg/ppc/tcg-target.c.inc | 10 ++++++---- tcg/riscv/tcg-target.c.inc | 10 ++++++---- tcg/s390x/tcg-target.c.inc | 9 ++++++--- tcg/sparc64/tcg-target.c.inc | 12 ++++++------ tcg/tcg.c | 9 ++++++--- tcg/tci/tcg-target.c.inc | 12 ++++++------ 11 files changed, 72 insertions(+), 46 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index bd6da72678..fde3b30ad1 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -63,9 +63,13 @@ static const int tcg_target_call_iarg_regs[8] = { TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7 }; -static const int tcg_target_call_oarg_regs[1] = { - TCG_REG_X0 -}; + +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 1); + return TCG_REG_X0 + slot; +} #define TCG_REG_TMP TCG_REG_X30 #define TCG_VEC_TMP TCG_REG_V31 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 6e9e9b9b3f..d06ac60c15 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -79,9 +79,13 @@ static const int tcg_target_reg_alloc_order[] = { static const int tcg_target_call_iarg_regs[4] = { TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 }; -static const int tcg_target_call_oarg_regs[2] = { - TCG_REG_R0, TCG_REG_R1 -}; + +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 3); + return TCG_REG_R0 + slot; +} #define TCG_REG_TMP TCG_REG_R12 #define TCG_VEC_TMP TCG_REG_Q15 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 7b573bd287..2f0a9521bf 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -109,12 +109,16 @@ static const int tcg_target_call_iarg_regs[] = { #endif }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_EAX, -#if TCG_TARGET_REG_BITS == 32 - TCG_REG_EDX -#endif -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + switch (kind) { + case TCG_CALL_RET_NORMAL: + tcg_debug_assert(slot >= 0 && slot <= 1); + return slot ? TCG_REG_EDX : TCG_REG_EAX; + default: + g_assert_not_reached(); + } +} /* Constants we accept. */ #define TCG_CT_CONST_S32 0x100 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b6e2ff6213..c5f55afd68 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -114,10 +114,12 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_A7, }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_A0, - TCG_REG_A1, -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 1); + return TCG_REG_A0 + slot; +} #ifndef CONFIG_SOFTMMU #define USE_GUEST_BASE (guest_base != 0) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index d419c4c1fc..80748d892e 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -136,10 +136,12 @@ static const TCGReg tcg_target_call_iarg_regs[] = { #endif }; -static const TCGReg tcg_target_call_oarg_regs[2] = { - TCG_REG_V0, - TCG_REG_V1 -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 1); + return TCG_REG_V0 + slot; +} static const tcg_insn_unit *tb_ret_addr; static const tcg_insn_unit *bswap32_addr; diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 85f84fe59e..f3fec14118 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -186,10 +186,12 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_R10 }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_R3, - TCG_REG_R4 -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 1); + return TCG_REG_R3 + slot; +} static const int tcg_target_callee_save_regs[] = { #ifdef _CALL_DARWIN diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 383331025a..558de127ef 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -113,10 +113,12 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_A7, }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_A0, - TCG_REG_A1, -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 1); + return TCG_REG_A0 + slot; +} #define TCG_CT_CONST_ZERO 0x100 #define TCG_CT_CONST_S12 0x200 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index d8fd755ef0..844532156b 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -402,9 +402,12 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_R6, }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_R2, -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot == 0); + return TCG_REG_R2; +} #define S390_CC_EQ 8 #define S390_CC_LT 4 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 4b834f3f1e..ccc4144f7c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -132,12 +132,12 @@ static const int tcg_target_call_iarg_regs[6] = { TCG_REG_O5, }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_O0, - TCG_REG_O1, - TCG_REG_O2, - TCG_REG_O3, -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot <= 3); + return TCG_REG_O0 + slot; +} #define INSN_OP(x) ((x) << 30) #define INSN_OP2(x) ((x) << 22) diff --git a/tcg/tcg.c b/tcg/tcg.c index 123cde7000..a77483eee8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -151,6 +151,7 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, intptr_t ofs); static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, const TCGHelperInfo *info); +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot); static bool tcg_target_const_match(int64_t val, TCGType type, int ct); #ifdef TCG_TARGET_NEED_LDST_LABELS static int tcg_out_ldst_finalize(TCGContext *s); @@ -740,14 +741,16 @@ static void init_call_layout(TCGHelperInfo *info) case dh_typecode_s64: info->nr_out = 64 / TCG_TARGET_REG_BITS; info->out_kind = TCG_CALL_RET_NORMAL; - assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); + /* Query the last register now to trigger any assert early. */ + tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); break; case dh_typecode_i128: info->nr_out = 128 / TCG_TARGET_REG_BITS; info->out_kind = TCG_CALL_RET_NORMAL; /* TODO */ switch (/* TODO */ TCG_CALL_RET_NORMAL) { case TCG_CALL_RET_NORMAL: - assert(info->nr_out <= ARRAY_SIZE(tcg_target_call_oarg_regs)); + /* Query the last register now to trigger any assert early. */ + tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); break; case TCG_CALL_RET_BY_REF: /* @@ -4592,7 +4595,7 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) case TCG_CALL_RET_NORMAL: for (i = 0; i < nb_oargs; i++) { TCGTemp *ts = arg_temp(op->args[i]); - TCGReg reg = tcg_target_call_oarg_regs[i]; + TCGReg reg = tcg_target_call_oarg_reg(TCG_CALL_RET_NORMAL, i); /* ENV should not be modified. */ tcg_debug_assert(!temp_readonly(ts)); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 33551b43dc..e3b0ff303f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -200,12 +200,12 @@ static const int tcg_target_reg_alloc_order[] = { /* No call arguments via registers. All will be stored on the "stack". */ static const int tcg_target_call_iarg_regs[] = { }; -static const int tcg_target_call_oarg_regs[] = { - TCG_REG_R0, -#if TCG_TARGET_REG_BITS == 32 - TCG_REG_R1 -#endif -}; +static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) +{ + tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); + tcg_debug_assert(slot >= 0 && slot < 64 / TCG_TARGET_REG_BITS); + return TCG_REG_R0 + slot; +} #ifdef CONFIG_DEBUG_TCG static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { From c6556aa0c8de8718813fea0ca61232632bf33c42 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 01:13:52 +1000 Subject: [PATCH 478/814] tcg: Add TCG_CALL_RET_BY_VEC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be used by _WIN64 to return i128. Not yet used, because allocation is not yet enabled. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg-internal.h | 1 + tcg/tcg.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index 2ec1ea01df..33f1d8b411 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -37,6 +37,7 @@ typedef enum { TCG_CALL_RET_NORMAL, /* by registers */ TCG_CALL_RET_BY_REF, /* for i128, by reference */ + TCG_CALL_RET_BY_VEC, /* for i128, by vector register */ } TCGCallReturnKind; typedef enum { diff --git a/tcg/tcg.c b/tcg/tcg.c index a77483eee8..098be83b00 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -752,6 +752,10 @@ static void init_call_layout(TCGHelperInfo *info) /* Query the last register now to trigger any assert early. */ tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); break; + case TCG_CALL_RET_BY_VEC: + /* Query the single register now to trigger any assert early. */ + tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0); + break; case TCG_CALL_RET_BY_REF: /* * Allocate the first argument to the output. @@ -4605,6 +4609,21 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) } break; + case TCG_CALL_RET_BY_VEC: + { + TCGTemp *ts = arg_temp(op->args[0]); + + tcg_debug_assert(ts->base_type == TCG_TYPE_I128); + tcg_debug_assert(ts->temp_subindex == 0); + if (!ts->mem_allocated) { + temp_allocate_frame(s, ts); + } + tcg_out_st(s, TCG_TYPE_V128, + tcg_target_call_oarg_reg(TCG_CALL_RET_BY_VEC, 0), + ts->mem_base->reg, ts->mem_offset); + } + /* fall through to mark all parts in memory */ + case TCG_CALL_RET_BY_REF: /* The callee has performed a write through the reference. */ for (i = 0; i < nb_oargs; i++) { From b959822c94e6d32b36fad038e79c14f841e585c1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Oct 2022 09:17:20 +1000 Subject: [PATCH 479/814] include/qemu/int128: Use Int128 structure for TCI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are about to allow passing Int128 to/from tcg helper functions, but libffi doesn't support __int128_t, so use the structure. In order for atomic128.h to continue working, we must provide a mechanism to frob between real __int128_t and the structure. Provide a new union, Int128Alias, for this. We cannot modify Int128 itself, as any changed alignment would also break libffi. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/qemu/atomic128.h | 29 +++++++++++++++++++++------ include/qemu/int128.h | 25 +++++++++++++++++++++--- util/int128.c | 42 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/include/qemu/atomic128.h b/include/qemu/atomic128.h index adb9a1a260..d0ba0b9c65 100644 --- a/include/qemu/atomic128.h +++ b/include/qemu/atomic128.h @@ -44,13 +44,23 @@ #if defined(CONFIG_ATOMIC128) static inline Int128 atomic16_cmpxchg(Int128 *ptr, Int128 cmp, Int128 new) { - return qatomic_cmpxchg__nocheck(ptr, cmp, new); + Int128Alias r, c, n; + + c.s = cmp; + n.s = new; + r.i = qatomic_cmpxchg__nocheck((__int128_t *)ptr, c.i, n.i); + return r.s; } # define HAVE_CMPXCHG128 1 #elif defined(CONFIG_CMPXCHG128) static inline Int128 atomic16_cmpxchg(Int128 *ptr, Int128 cmp, Int128 new) { - return __sync_val_compare_and_swap_16(ptr, cmp, new); + Int128Alias r, c, n; + + c.s = cmp; + n.s = new; + r.i = __sync_val_compare_and_swap_16((__int128_t *)ptr, c.i, n.i); + return r.s; } # define HAVE_CMPXCHG128 1 #elif defined(__aarch64__) @@ -89,12 +99,18 @@ Int128 QEMU_ERROR("unsupported atomic") #if defined(CONFIG_ATOMIC128) static inline Int128 atomic16_read(Int128 *ptr) { - return qatomic_read__nocheck(ptr); + Int128Alias r; + + r.i = qatomic_read__nocheck((__int128_t *)ptr); + return r.s; } static inline void atomic16_set(Int128 *ptr, Int128 val) { - qatomic_set__nocheck(ptr, val); + Int128Alias v; + + v.s = val; + qatomic_set__nocheck((__int128_t *)ptr, v.i); } # define HAVE_ATOMIC128 1 @@ -132,7 +148,8 @@ static inline void atomic16_set(Int128 *ptr, Int128 val) static inline Int128 atomic16_read(Int128 *ptr) { /* Maybe replace 0 with 0, returning the old value. */ - return atomic16_cmpxchg(ptr, 0, 0); + Int128 z = int128_make64(0); + return atomic16_cmpxchg(ptr, z, z); } static inline void atomic16_set(Int128 *ptr, Int128 val) @@ -141,7 +158,7 @@ static inline void atomic16_set(Int128 *ptr, Int128 val) do { cmp = old; old = atomic16_cmpxchg(ptr, cmp, val); - } while (old != cmp); + } while (int128_ne(old, cmp)); } # define HAVE_ATOMIC128 1 diff --git a/include/qemu/int128.h b/include/qemu/int128.h index d2b76ca6ac..f62a46b48c 100644 --- a/include/qemu/int128.h +++ b/include/qemu/int128.h @@ -3,7 +3,12 @@ #include "qemu/bswap.h" -#ifdef CONFIG_INT128 +/* + * With TCI, we need to use libffi for interfacing with TCG helpers. + * But libffi does not support __int128_t, and therefore cannot pass + * or return values of this type, force use of the Int128 struct. + */ +#if defined(CONFIG_INT128) && !defined(CONFIG_TCG_INTERPRETER) typedef __int128_t Int128; static inline Int128 int128_make64(uint64_t a) @@ -460,8 +465,7 @@ Int128 int128_divu(Int128, Int128); Int128 int128_remu(Int128, Int128); Int128 int128_divs(Int128, Int128); Int128 int128_rems(Int128, Int128); - -#endif /* CONFIG_INT128 */ +#endif /* CONFIG_INT128 && !CONFIG_TCG_INTERPRETER */ static inline void bswap128s(Int128 *s) { @@ -472,4 +476,19 @@ static inline void bswap128s(Int128 *s) #define INT128_MAX int128_make128(UINT64_MAX, INT64_MAX) #define INT128_MIN int128_make128(0, INT64_MIN) +/* + * When compiler supports a 128-bit type, define a combination of + * a possible structure and the native types. Ease parameter passing + * via use of the transparent union extension. + */ +#ifdef CONFIG_INT128 +typedef union { + Int128 s; + __int128_t i; + __uint128_t u; +} Int128Alias __attribute__((transparent_union)); +#else +typedef Int128 Int128Alias; +#endif /* CONFIG_INT128 */ + #endif /* INT128_H */ diff --git a/util/int128.c b/util/int128.c index ed8f25fef1..df6c6331bd 100644 --- a/util/int128.c +++ b/util/int128.c @@ -144,4 +144,46 @@ Int128 int128_rems(Int128 a, Int128 b) return r; } +#elif defined(CONFIG_TCG_INTERPRETER) + +Int128 int128_divu(Int128 a_s, Int128 b_s) +{ + Int128Alias r, a, b; + + a.s = a_s; + b.s = b_s; + r.u = a.u / b.u; + return r.s; +} + +Int128 int128_remu(Int128 a_s, Int128 b_s) +{ + Int128Alias r, a, b; + + a.s = a_s; + b.s = b_s; + r.u = a.u % b.u; + return r.s; +} + +Int128 int128_divs(Int128 a_s, Int128 b_s) +{ + Int128Alias r, a, b; + + a.s = a_s; + b.s = b_s; + r.i = a.i / b.i; + return r.s; +} + +Int128 int128_rems(Int128 a_s, Int128 b_s) +{ + Int128Alias r, a, b; + + a.s = a_s; + b.s = b_s; + r.i = a.i % b.i; + return r.s; +} + #endif From c4f4a00ac7d947c9b100e3cb62755a9a157df1fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 10:16:28 +1000 Subject: [PATCH 480/814] tcg/i386: Add TCG_TARGET_CALL_{RET,ARG}_I128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill in the parameters for the host ABI for Int128. Adjust tcg_target_call_oarg_reg for _WIN64, and tcg_out_call for i386 sysv. Allow TCG_TYPE_V128 stores without AVX enabled. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 30 +++++++++++++++++++++++++++++- tcg/i386/tcg-target.h | 10 ++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 2f0a9521bf..883ced8168 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -115,6 +115,11 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) case TCG_CALL_RET_NORMAL: tcg_debug_assert(slot >= 0 && slot <= 1); return slot ? TCG_REG_EDX : TCG_REG_EAX; +#ifdef _WIN64 + case TCG_CALL_RET_BY_VEC: + tcg_debug_assert(slot == 0); + return TCG_REG_XMM0; +#endif default: g_assert_not_reached(); } @@ -1188,9 +1193,16 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, * The gvec infrastructure is asserts that v128 vector loads * and stores use a 16-byte aligned offset. Validate that the * final pointer is aligned by using an insn that will SIGSEGV. + * + * This specific instance is also used by TCG_CALL_RET_BY_VEC, + * for _WIN64, which must have SSE2 but may not have AVX. */ tcg_debug_assert(arg >= 16); - tcg_out_vex_modrm_offset(s, OPC_MOVDQA_WxVx, arg, 0, arg1, arg2); + if (have_avx1) { + tcg_out_vex_modrm_offset(s, OPC_MOVDQA_WxVx, arg, 0, arg1, arg2); + } else { + tcg_out_modrm_offset(s, OPC_MOVDQA_WxVx, arg, arg1, arg2); + } break; case TCG_TYPE_V256: /* @@ -1677,6 +1689,22 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, const TCGHelperInfo *info) { tcg_out_branch(s, 1, dest); + +#ifndef _WIN32 + if (TCG_TARGET_REG_BITS == 32 && info->out_kind == TCG_CALL_RET_BY_REF) { + /* + * The sysv i386 abi for struct return places a reference as the + * first argument of the stack, and pops that argument with the + * return statement. Since we want to retain the aligned stack + * pointer for the callee, we do not want to actually push that + * argument before the call but rely on the normal store to the + * stack slot. But we do need to compensate for the pop in order + * to reset our correct stack pointer value. + * Pushing a garbage value back onto the stack is quickest. + */ + tcg_out_push(s, TCG_REG_EAX); + } +#endif } static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest) diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 5797a55ea0..d4f2a6f8c2 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -100,6 +100,16 @@ typedef enum { #endif #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#if defined(_WIN64) +# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_BY_REF +# define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_VEC +#elif TCG_TARGET_REG_BITS == 64 +# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL +# define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL +#else +# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL +# define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF +#endif extern bool have_bmi1; extern bool have_popcnt; From 896c76e6ba5d9a3444fb8528fdc407747ecc82f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 10:34:21 +1000 Subject: [PATCH 481/814] tcg/tci: Fix big-endian return register ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We expect the backend to require register pairs in host-endian ordering, thus for big-endian the first register of a pair contains the high part. We were forcing R0 to contain the low part for calls. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tci.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tcg/tci.c b/tcg/tci.c index 05a24163d3..eeccdde8bc 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -520,27 +520,28 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, ffi_call(pptr[1], pptr[0], stack, call_slots); } - /* Any result winds up "left-aligned" in the stack[0] slot. */ switch (len) { case 0: /* void */ break; case 1: /* uint32_t */ /* + * The result winds up "left-aligned" in the stack[0] slot. * Note that libffi has an odd special case in that it will * always widen an integral result to ffi_arg. */ - if (sizeof(ffi_arg) == 4) { - regs[TCG_REG_R0] = *(uint32_t *)stack; - break; - } - /* fall through */ - case 2: /* uint64_t */ - if (TCG_TARGET_REG_BITS == 32) { - tci_write_reg64(regs, TCG_REG_R1, TCG_REG_R0, stack[0]); + if (sizeof(ffi_arg) == 8) { + regs[TCG_REG_R0] = (uint32_t)stack[0]; } else { - regs[TCG_REG_R0] = stack[0]; + regs[TCG_REG_R0] = *(uint32_t *)stack; } break; + case 2: /* uint64_t */ + /* + * For TCG_TARGET_REG_BITS == 32, the register pair + * must stay in host memory order. + */ + memcpy(®s[TCG_REG_R0], stack, 8); + break; default: g_assert_not_reached(); } From e9709e17ac88f16c60004c4160c9a131d36ed564 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 10:47:54 +1000 Subject: [PATCH 482/814] tcg/tci: Add TCG_TARGET_CALL_{RET,ARG}_I128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill in the parameters for libffi for Int128. Adjust the interpreter to allow for 16-byte return values. Adjust tcg_out_call to record the return value length. Call parameters are no longer all the same size, so we cannot reuse the same call_slots array for every function. Compute it each time now, but only fill in slots required for the call we're about to make. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- tcg/tcg.c | 19 +++++++++++++++++ tcg/tci.c | 44 ++++++++++++++++++++-------------------- tcg/tci/tcg-target.c.inc | 10 ++++----- tcg/tci/tcg-target.h | 3 +++ 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 098be83b00..865ed5ea0f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -570,6 +570,22 @@ static GHashTable *helper_table; #ifdef CONFIG_TCG_INTERPRETER static ffi_type *typecode_to_ffi(int argmask) { + /* + * libffi does not support __int128_t, so we have forced Int128 + * to use the structure definition instead of the builtin type. + */ + static ffi_type *ffi_type_i128_elements[3] = { + &ffi_type_uint64, + &ffi_type_uint64, + NULL + }; + static ffi_type ffi_type_i128 = { + .size = 16, + .alignment = __alignof__(Int128), + .type = FFI_TYPE_STRUCT, + .elements = ffi_type_i128_elements, + }; + switch (argmask) { case dh_typecode_void: return &ffi_type_void; @@ -583,6 +599,8 @@ static ffi_type *typecode_to_ffi(int argmask) return &ffi_type_sint64; case dh_typecode_ptr: return &ffi_type_pointer; + case dh_typecode_i128: + return &ffi_type_i128; } g_assert_not_reached(); } @@ -613,6 +631,7 @@ static void init_ffi_layouts(void) /* Ignoring the return type, find the last non-zero field. */ nargs = 32 - clz32(typemask >> 3); nargs = DIV_ROUND_UP(nargs, 3); + assert(nargs <= MAX_CALL_IARGS); ca = g_malloc0(sizeof(*ca) + nargs * sizeof(ffi_type *)); ca->cif.rtype = typecode_to_ffi(typemask & 7); diff --git a/tcg/tci.c b/tcg/tci.c index eeccdde8bc..022fe9d0f8 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -470,12 +470,9 @@ 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)]; - void *call_slots[TCG_STATIC_CALL_ARGS_SIZE / sizeof(uint64_t)]; regs[TCG_AREG0] = (tcg_target_ulong)env; regs[TCG_REG_CALL_STACK] = (uintptr_t)stack; - /* Other call_slots entries initialized at first use (see below). */ - call_slots[0] = NULL; tci_assert(tb_ptr); for (;;) { @@ -498,26 +495,26 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, switch (opc) { case INDEX_op_call: - /* - * Set up the ffi_avalue array once, delayed until now - * because many TB's do not make any calls. In tcg_gen_callN, - * we arranged for every real argument to be "left-aligned" - * in each 64-bit slot. - */ - if (unlikely(call_slots[0] == NULL)) { - for (int i = 0; i < ARRAY_SIZE(call_slots); ++i) { - call_slots[i] = &stack[i]; - } - } - - tci_args_nl(insn, tb_ptr, &len, &ptr); - - /* Helper functions may need to access the "return address" */ - tci_tb_ptr = (uintptr_t)tb_ptr; - { - void **pptr = ptr; - ffi_call(pptr[1], pptr[0], stack, call_slots); + void *call_slots[MAX_CALL_IARGS]; + ffi_cif *cif; + void *func; + unsigned i, s, n; + + tci_args_nl(insn, tb_ptr, &len, &ptr); + func = ((void **)ptr)[0]; + cif = ((void **)ptr)[1]; + + n = cif->nargs; + for (i = s = 0; i < n; ++i) { + ffi_type *t = cif->arg_types[i]; + call_slots[i] = &stack[s]; + s += DIV_ROUND_UP(t->size, 8); + } + + /* Helper functions may need to access the "return address" */ + tci_tb_ptr = (uintptr_t)tb_ptr; + ffi_call(cif, func, stack, call_slots); } switch (len) { @@ -542,6 +539,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, */ memcpy(®s[TCG_REG_R0], stack, 8); break; + case 3: /* Int128 */ + memcpy(®s[TCG_REG_R0], stack, 16); + break; default: g_assert_not_reached(); } diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index e3b0ff303f..c1d34d7bd1 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -203,7 +203,7 @@ static const int tcg_target_call_iarg_regs[] = { }; static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) { tcg_debug_assert(kind == TCG_CALL_RET_NORMAL); - tcg_debug_assert(slot >= 0 && slot < 64 / TCG_TARGET_REG_BITS); + tcg_debug_assert(slot >= 0 && slot < 128 / TCG_TARGET_REG_BITS); return TCG_REG_R0 + slot; } @@ -573,11 +573,11 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, if (cif->rtype == &ffi_type_void) { which = 0; - } else if (cif->rtype->size == 4) { - which = 1; } else { - tcg_debug_assert(cif->rtype->size == 8); - which = 2; + tcg_debug_assert(cif->rtype->size == 4 || + cif->rtype->size == 8 || + cif->rtype->size == 16); + which = ctz32(cif->rtype->size) - 1; } new_pool_l2(s, 20, s->code_ptr, 0, (uintptr_t)func, (uintptr_t)cif); insn = deposit32(insn, 0, 8, INDEX_op_call); diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 1414ab4d5b..7140a76a73 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -160,10 +160,13 @@ typedef enum { #if TCG_TARGET_REG_BITS == 32 # define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EVEN # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_EVEN #else # define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +# define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL #endif +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL #define HAVE_TCG_QEMU_TB_EXEC #define TCG_TARGET_NEED_POOL_LABELS From 5427a9a76041029730775292995e87c3edd06515 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 07:54:48 +1000 Subject: [PATCH 483/814] tcg: Add TCG_TARGET_CALL_{RET,ARG}_I128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill in the parameters for the host ABI for Int128 for those backends which require no extra modification. Reviewed-by: Alex Bennée Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.h | 2 ++ tcg/arm/tcg-target.h | 2 ++ tcg/loongarch64/tcg-target.h | 2 ++ tcg/mips/tcg-target.h | 2 ++ tcg/ppc/tcg-target.c.inc | 3 +++ tcg/riscv/tcg-target.h | 3 +++ tcg/s390x/tcg-target.h | 2 ++ tcg/sparc64/tcg-target.h | 2 ++ tcg/tcg.c | 6 +++--- 9 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 8d244292aa..c0b0f614ba 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -54,6 +54,8 @@ typedef enum { #define TCG_TARGET_CALL_STACK_OFFSET 0 #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_EVEN +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 91b8954804..def2a189e6 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -91,6 +91,8 @@ extern bool use_neon_instructions; #define TCG_TARGET_CALL_STACK_OFFSET 0 #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_EVEN +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF /* optional instructions */ #define TCG_TARGET_HAS_ext8s_i32 1 diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 8b151e7f6f..17b8193aa5 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -92,6 +92,8 @@ typedef enum { #define TCG_TARGET_CALL_STACK_OFFSET 0 #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 1 diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 7bc8e15293..68b11e4d48 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -89,6 +89,8 @@ typedef enum { # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL #endif #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_EVEN +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL /* MOVN/MOVZ instructions detection */ #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index f3fec14118..afadf9a1e3 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -54,6 +54,9 @@ #else # define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL #endif +/* Note sysv arg alignment applies only to 2-word types, not more. */ +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL /* For some memory operations, we need a scratch that isn't R0. For the AIX calling convention, we can re-use the TOC register since we'll be reloading diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index 1337bc1f1e..0deb33701f 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -85,9 +85,12 @@ typedef enum { #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL #if TCG_TARGET_REG_BITS == 32 #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_EVEN +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_EVEN #else #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL #endif +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 0 diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index e597e47e60..a05b473117 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -169,6 +169,8 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_CALL_STACK_OFFSET 160 #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_BY_REF +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_BY_REF #define TCG_TARGET_HAS_MEMORY_BSWAP 1 diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 1d6a5c8b07..ffe22b1d21 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -73,6 +73,8 @@ typedef enum { #define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS) #define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_EXTEND #define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL +#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL #if defined(__VIS__) && __VIS__ >= 0x300 #define use_vis3_instructions 1 diff --git a/tcg/tcg.c b/tcg/tcg.c index 865ed5ea0f..163913c95f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -765,8 +765,8 @@ static void init_call_layout(TCGHelperInfo *info) break; case dh_typecode_i128: info->nr_out = 128 / TCG_TARGET_REG_BITS; - info->out_kind = TCG_CALL_RET_NORMAL; /* TODO */ - switch (/* TODO */ TCG_CALL_RET_NORMAL) { + info->out_kind = TCG_TARGET_CALL_RET_I128; + switch (TCG_TARGET_CALL_RET_I128) { case TCG_CALL_RET_NORMAL: /* Query the last register now to trigger any assert early. */ tcg_target_call_oarg_reg(info->out_kind, info->nr_out - 1); @@ -854,7 +854,7 @@ static void init_call_layout(TCGHelperInfo *info) break; case TCG_TYPE_I128: - switch (/* TODO */ TCG_CALL_ARG_NORMAL) { + switch (TCG_TARGET_CALL_ARG_I128) { case TCG_CALL_ARG_EVEN: layout_arg_even(&cum); /* fall through */ From 43eef72f41093ae4a94ffddc94aeef80a2fb5c69 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 08:03:41 +1000 Subject: [PATCH 484/814] tcg: Add temp allocation for TCGv_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables allocation of i128. The type is not yet usable, as we have not yet added data movement ops. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg.h | 32 +++++++++++++++++++++++++ tcg/tcg.c | 60 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 4d7e4107a9..59854f95b1 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -687,6 +687,11 @@ static inline TCGTemp *tcgv_i64_temp(TCGv_i64 v) return tcgv_i32_temp((TCGv_i32)v); } +static inline TCGTemp *tcgv_i128_temp(TCGv_i128 v) +{ + return tcgv_i32_temp((TCGv_i32)v); +} + static inline TCGTemp *tcgv_ptr_temp(TCGv_ptr v) { return tcgv_i32_temp((TCGv_i32)v); @@ -707,6 +712,11 @@ static inline TCGArg tcgv_i64_arg(TCGv_i64 v) return temp_arg(tcgv_i64_temp(v)); } +static inline TCGArg tcgv_i128_arg(TCGv_i128 v) +{ + return temp_arg(tcgv_i128_temp(v)); +} + static inline TCGArg tcgv_ptr_arg(TCGv_ptr v) { return temp_arg(tcgv_ptr_temp(v)); @@ -728,6 +738,11 @@ static inline TCGv_i64 temp_tcgv_i64(TCGTemp *t) return (TCGv_i64)temp_tcgv_i32(t); } +static inline TCGv_i128 temp_tcgv_i128(TCGTemp *t) +{ + return (TCGv_i128)temp_tcgv_i32(t); +} + static inline TCGv_ptr temp_tcgv_ptr(TCGTemp *t) { return (TCGv_ptr)temp_tcgv_i32(t); @@ -853,6 +868,11 @@ static inline void tcg_temp_free_i64(TCGv_i64 arg) tcg_temp_free_internal(tcgv_i64_temp(arg)); } +static inline void tcg_temp_free_i128(TCGv_i128 arg) +{ + tcg_temp_free_internal(tcgv_i128_temp(arg)); +} + static inline void tcg_temp_free_ptr(TCGv_ptr arg) { tcg_temp_free_internal(tcgv_ptr_temp(arg)); @@ -901,6 +921,18 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void) return temp_tcgv_i64(t); } +static inline TCGv_i128 tcg_temp_new_i128(void) +{ + TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I128, false); + return temp_tcgv_i128(t); +} + +static inline TCGv_i128 tcg_temp_local_new_i128(void) +{ + TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I128, true); + return temp_tcgv_i128(t); +} + static inline TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t offset, const char *name) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 163913c95f..a4a3da6804 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1273,26 +1273,45 @@ TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local) tcg_debug_assert(ts->base_type == type); tcg_debug_assert(ts->kind == kind); } else { + int i, n; + + switch (type) { + case TCG_TYPE_I32: + case TCG_TYPE_V64: + case TCG_TYPE_V128: + case TCG_TYPE_V256: + n = 1; + break; + case TCG_TYPE_I64: + n = 64 / TCG_TARGET_REG_BITS; + break; + case TCG_TYPE_I128: + n = 128 / TCG_TARGET_REG_BITS; + break; + default: + g_assert_not_reached(); + } + ts = tcg_temp_alloc(s); - if (TCG_TARGET_REG_BITS == 32 && type == TCG_TYPE_I64) { - TCGTemp *ts2 = tcg_temp_alloc(s); + ts->base_type = type; + ts->temp_allocated = 1; + ts->kind = kind; - ts->base_type = type; - ts->type = TCG_TYPE_I32; - ts->temp_allocated = 1; - ts->kind = kind; - - tcg_debug_assert(ts2 == ts + 1); - ts2->base_type = TCG_TYPE_I64; - ts2->type = TCG_TYPE_I32; - ts2->temp_allocated = 1; - ts2->temp_subindex = 1; - ts2->kind = kind; - } else { - ts->base_type = type; + if (n == 1) { ts->type = type; - ts->temp_allocated = 1; - ts->kind = kind; + } else { + ts->type = TCG_TYPE_REG; + + for (i = 1; i < n; ++i) { + TCGTemp *ts2 = tcg_temp_alloc(s); + + tcg_debug_assert(ts2 == ts + i); + ts2->base_type = type; + ts2->type = TCG_TYPE_REG; + ts2->temp_allocated = 1; + ts2->temp_subindex = i; + ts2->kind = kind; + } } } @@ -3384,9 +3403,14 @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts) case TCG_TYPE_V64: align = 8; break; + case TCG_TYPE_I128: case TCG_TYPE_V128: case TCG_TYPE_V256: - /* Note that we do not require aligned storage for V256. */ + /* + * Note that we do not require aligned storage for V256, + * and that we provide alignment for I128 to match V128, + * even if that's above what the host ABI requires. + */ align = 16; break; default: From 4771e71c28eb0cece2a17a2d891bbd724bdc158d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 08:00:51 +1000 Subject: [PATCH 485/814] tcg: Add basic data movement for TCGv_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add code generation functions for data movement between TCGv_i128 (mov) and to/from TCGv_i64 (concat, extract). Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 4 ++++ tcg/tcg-internal.h | 13 +++++++++++++ tcg/tcg-op.c | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 79b1cf786f..c4276767d1 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -712,6 +712,10 @@ void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg); void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg); void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg); +void tcg_gen_mov_i128(TCGv_i128 dst, TCGv_i128 src); +void tcg_gen_extr_i128_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i128 arg); +void tcg_gen_concat_i64_i128(TCGv_i128 ret, TCGv_i64 lo, TCGv_i64 hi); + static inline void tcg_gen_concat32_i64(TCGv_i64 ret, TCGv_i64 lo, TCGv_i64 hi) { tcg_gen_deposit_i64(ret, lo, hi, 32, 32); diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index 33f1d8b411..e542a4e9b7 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -117,4 +117,17 @@ extern TCGv_i32 TCGV_LOW(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); extern TCGv_i32 TCGV_HIGH(TCGv_i64) QEMU_ERROR("32-bit code path is reachable"); #endif +static inline TCGv_i64 TCGV128_LOW(TCGv_i128 t) +{ + /* For 32-bit, offset by 2, which may then have TCGV_{LOW,HIGH} applied. */ + int o = HOST_BIG_ENDIAN ? 64 / TCG_TARGET_REG_BITS : 0; + return temp_tcgv_i64(tcgv_i128_temp(t) + o); +} + +static inline TCGv_i64 TCGV128_HIGH(TCGv_i128 t) +{ + int o = HOST_BIG_ENDIAN ? 0 : 64 / TCG_TARGET_REG_BITS; + return temp_tcgv_i64(tcgv_i128_temp(t) + o); +} + #endif /* TCG_INTERNAL_H */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 326a9180ef..cb83d2375d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2747,6 +2747,26 @@ void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg) tcg_gen_shri_i64(hi, arg, 32); } +void tcg_gen_extr_i128_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i128 arg) +{ + tcg_gen_mov_i64(lo, TCGV128_LOW(arg)); + tcg_gen_mov_i64(hi, TCGV128_HIGH(arg)); +} + +void tcg_gen_concat_i64_i128(TCGv_i128 ret, TCGv_i64 lo, TCGv_i64 hi) +{ + tcg_gen_mov_i64(TCGV128_LOW(ret), lo); + tcg_gen_mov_i64(TCGV128_HIGH(ret), hi); +} + +void tcg_gen_mov_i128(TCGv_i128 dst, TCGv_i128 src) +{ + if (dst != src) { + tcg_gen_mov_i64(TCGV128_LOW(dst), TCGV128_LOW(src)); + tcg_gen_mov_i64(TCGV128_HIGH(dst), TCGV128_HIGH(src)); + } +} + /* QEMU specific operations. */ void tcg_gen_exit_tb(const TranslationBlock *tb, unsigned idx) From cb48f3654e290ee5d7cbf1fb31888463fa2a180c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 7 Nov 2022 19:48:14 +1100 Subject: [PATCH 486/814] tcg: Add guest load/store primitives for TCGv_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are not yet considering atomicity of the 16-byte value; this is a direct replacement for the current target code which uses a pair of 8-byte operations. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 112 +++++++++++++++++++++++++++++++++ accel/tcg/user-exec.c | 66 ++++++++++++++++++++ include/exec/cpu_ldst.h | 10 +++ include/tcg/tcg-op.h | 2 + tcg/tcg-op.c | 134 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 324 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 04e270742e..4812d83961 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2192,6 +2192,64 @@ uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr, return cpu_load_helper(env, addr, oi, ra, helper_le_ldq_mmu); } +Int128 cpu_ld16_be_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + MemOp mop = get_memop(oi); + int mmu_idx = get_mmuidx(oi); + MemOpIdx new_oi; + unsigned a_bits; + uint64_t h, l; + + tcg_debug_assert((mop & (MO_BSWAP|MO_SSIZE)) == (MO_BE|MO_128)); + a_bits = get_alignment_bits(mop); + + /* Handle CPU specific unaligned behaviour */ + if (addr & ((1 << a_bits) - 1)) { + cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_LOAD, + mmu_idx, ra); + } + + /* Construct an unaligned 64-bit replacement MemOpIdx. */ + mop = (mop & ~(MO_SIZE | MO_AMASK)) | MO_64 | MO_UNALN; + new_oi = make_memop_idx(mop, mmu_idx); + + h = helper_be_ldq_mmu(env, addr, new_oi, ra); + l = helper_be_ldq_mmu(env, addr + 8, new_oi, ra); + + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); + return int128_make128(l, h); +} + +Int128 cpu_ld16_le_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + MemOp mop = get_memop(oi); + int mmu_idx = get_mmuidx(oi); + MemOpIdx new_oi; + unsigned a_bits; + uint64_t h, l; + + tcg_debug_assert((mop & (MO_BSWAP|MO_SSIZE)) == (MO_LE|MO_128)); + a_bits = get_alignment_bits(mop); + + /* Handle CPU specific unaligned behaviour */ + if (addr & ((1 << a_bits) - 1)) { + cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_LOAD, + mmu_idx, ra); + } + + /* Construct an unaligned 64-bit replacement MemOpIdx. */ + mop = (mop & ~(MO_SIZE | MO_AMASK)) | MO_64 | MO_UNALN; + new_oi = make_memop_idx(mop, mmu_idx); + + l = helper_le_ldq_mmu(env, addr, new_oi, ra); + h = helper_le_ldq_mmu(env, addr + 8, new_oi, ra); + + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); + return int128_make128(l, h); +} + /* * Store Helpers */ @@ -2546,6 +2604,60 @@ void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val, cpu_store_helper(env, addr, val, oi, retaddr, helper_le_stq_mmu); } +void cpu_st16_be_mmu(CPUArchState *env, abi_ptr addr, Int128 val, + MemOpIdx oi, uintptr_t ra) +{ + MemOp mop = get_memop(oi); + int mmu_idx = get_mmuidx(oi); + MemOpIdx new_oi; + unsigned a_bits; + + tcg_debug_assert((mop & (MO_BSWAP|MO_SSIZE)) == (MO_BE|MO_128)); + a_bits = get_alignment_bits(mop); + + /* Handle CPU specific unaligned behaviour */ + if (addr & ((1 << a_bits) - 1)) { + cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, + mmu_idx, ra); + } + + /* Construct an unaligned 64-bit replacement MemOpIdx. */ + mop = (mop & ~(MO_SIZE | MO_AMASK)) | MO_64 | MO_UNALN; + new_oi = make_memop_idx(mop, mmu_idx); + + helper_be_stq_mmu(env, addr, int128_gethi(val), new_oi, ra); + helper_be_stq_mmu(env, addr + 8, int128_getlo(val), new_oi, ra); + + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); +} + +void cpu_st16_le_mmu(CPUArchState *env, abi_ptr addr, Int128 val, + MemOpIdx oi, uintptr_t ra) +{ + MemOp mop = get_memop(oi); + int mmu_idx = get_mmuidx(oi); + MemOpIdx new_oi; + unsigned a_bits; + + tcg_debug_assert((mop & (MO_BSWAP|MO_SSIZE)) == (MO_LE|MO_128)); + a_bits = get_alignment_bits(mop); + + /* Handle CPU specific unaligned behaviour */ + if (addr & ((1 << a_bits) - 1)) { + cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, + mmu_idx, ra); + } + + /* Construct an unaligned 64-bit replacement MemOpIdx. */ + mop = (mop & ~(MO_SIZE | MO_AMASK)) | MO_64 | MO_UNALN; + new_oi = make_memop_idx(mop, mmu_idx); + + helper_le_stq_mmu(env, addr, int128_getlo(val), new_oi, ra); + helper_le_stq_mmu(env, addr + 8, int128_gethi(val), new_oi, ra); + + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); +} + #include "ldst_common.c.inc" /* diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index a8eb63ab96..ae67d84638 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1031,6 +1031,42 @@ uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr, return ret; } +Int128 cpu_ld16_be_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + void *haddr; + Int128 ret; + + validate_memop(oi, MO_128 | MO_BE); + haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); + memcpy(&ret, haddr, 16); + clear_helper_retaddr(); + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); + + if (!HOST_BIG_ENDIAN) { + ret = bswap128(ret); + } + return ret; +} + +Int128 cpu_ld16_le_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra) +{ + void *haddr; + Int128 ret; + + validate_memop(oi, MO_128 | MO_LE); + haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); + memcpy(&ret, haddr, 16); + clear_helper_retaddr(); + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); + + if (HOST_BIG_ENDIAN) { + ret = bswap128(ret); + } + return ret; +} + void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, MemOpIdx oi, uintptr_t ra) { @@ -1115,6 +1151,36 @@ void cpu_stq_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } +void cpu_st16_be_mmu(CPUArchState *env, abi_ptr addr, + Int128 val, MemOpIdx oi, uintptr_t ra) +{ + void *haddr; + + validate_memop(oi, MO_128 | MO_BE); + haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); + if (!HOST_BIG_ENDIAN) { + val = bswap128(val); + } + memcpy(haddr, &val, 16); + clear_helper_retaddr(); + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); +} + +void cpu_st16_le_mmu(CPUArchState *env, abi_ptr addr, + Int128 val, MemOpIdx oi, uintptr_t ra) +{ + void *haddr; + + validate_memop(oi, MO_128 | MO_LE); + haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); + if (HOST_BIG_ENDIAN) { + val = bswap128(val); + } + memcpy(haddr, &val, 16); + clear_helper_retaddr(); + qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); +} + uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { uint32_t ret; diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index d0c7c0d5fe..09b55cc0ee 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -220,6 +220,11 @@ uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr ptr, uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra); +Int128 cpu_ld16_be_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra); +Int128 cpu_ld16_le_mmu(CPUArchState *env, abi_ptr addr, + MemOpIdx oi, uintptr_t ra); + void cpu_stb_mmu(CPUArchState *env, abi_ptr ptr, uint8_t val, MemOpIdx oi, uintptr_t ra); void cpu_stw_be_mmu(CPUArchState *env, abi_ptr ptr, uint16_t val, @@ -235,6 +240,11 @@ void cpu_stl_le_mmu(CPUArchState *env, abi_ptr ptr, uint32_t val, void cpu_stq_le_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val, MemOpIdx oi, uintptr_t ra); +void cpu_st16_be_mmu(CPUArchState *env, abi_ptr addr, Int128 val, + MemOpIdx oi, uintptr_t ra); +void cpu_st16_le_mmu(CPUArchState *env, abi_ptr addr, Int128 val, + MemOpIdx oi, uintptr_t ra); + uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, target_ulong addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index c4276767d1..e5f5b63c37 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -845,6 +845,8 @@ void tcg_gen_qemu_ld_i32(TCGv_i32, TCGv, TCGArg, MemOp); void tcg_gen_qemu_st_i32(TCGv_i32, TCGv, TCGArg, MemOp); void tcg_gen_qemu_ld_i64(TCGv_i64, TCGv, TCGArg, MemOp); void tcg_gen_qemu_st_i64(TCGv_i64, TCGv, TCGArg, MemOp); +void tcg_gen_qemu_ld_i128(TCGv_i128, TCGv, TCGArg, MemOp); +void tcg_gen_qemu_st_i128(TCGv_i128, TCGv, TCGArg, MemOp); static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index) { diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index cb83d2375d..33ef325f6e 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -3109,6 +3109,140 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop) } } +static void canonicalize_memop_i128_as_i64(MemOp ret[2], MemOp orig) +{ + MemOp mop_1 = orig, mop_2; + + tcg_debug_assert((orig & MO_SIZE) == MO_128); + tcg_debug_assert((orig & MO_SIGN) == 0); + + /* Use a memory ordering implemented by the host. */ + if (!TCG_TARGET_HAS_MEMORY_BSWAP && (orig & MO_BSWAP)) { + mop_1 &= ~MO_BSWAP; + } + + /* Reduce the size to 64-bit. */ + mop_1 = (mop_1 & ~MO_SIZE) | MO_64; + + /* Retain the alignment constraints of the original. */ + switch (orig & MO_AMASK) { + case MO_UNALN: + case MO_ALIGN_2: + case MO_ALIGN_4: + mop_2 = mop_1; + break; + case MO_ALIGN_8: + /* Prefer MO_ALIGN+MO_64 to MO_ALIGN_8+MO_64. */ + mop_1 = (mop_1 & ~MO_AMASK) | MO_ALIGN; + mop_2 = mop_1; + break; + case MO_ALIGN: + /* Second has 8-byte alignment; first has 16-byte alignment. */ + mop_2 = mop_1; + mop_1 = (mop_1 & ~MO_AMASK) | MO_ALIGN_16; + break; + case MO_ALIGN_16: + case MO_ALIGN_32: + case MO_ALIGN_64: + /* Second has 8-byte alignment; first retains original. */ + mop_2 = (mop_1 & ~MO_AMASK) | MO_ALIGN; + break; + default: + g_assert_not_reached(); + } + ret[0] = mop_1; + ret[1] = mop_2; +} + +void tcg_gen_qemu_ld_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop) +{ + MemOp mop[2]; + TCGv addr_p8; + TCGv_i64 x, y; + + canonicalize_memop_i128_as_i64(mop, memop); + + tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + addr = plugin_prep_mem_callbacks(addr); + + /* TODO: respect atomicity of the operation. */ + /* TODO: allow the tcg backend to see the whole operation. */ + + /* + * Since there are no global TCGv_i128, there is no visible state + * changed if the second load faults. Load directly into the two + * subwords. + */ + if ((memop & MO_BSWAP) == MO_LE) { + x = TCGV128_LOW(val); + y = TCGV128_HIGH(val); + } else { + x = TCGV128_HIGH(val); + y = TCGV128_LOW(val); + } + + gen_ldst_i64(INDEX_op_qemu_ld_i64, x, addr, mop[0], idx); + + if ((mop[0] ^ memop) & MO_BSWAP) { + tcg_gen_bswap64_i64(x, x); + } + + addr_p8 = tcg_temp_new(); + tcg_gen_addi_tl(addr_p8, addr, 8); + gen_ldst_i64(INDEX_op_qemu_ld_i64, y, addr_p8, mop[1], idx); + tcg_temp_free(addr_p8); + + if ((mop[0] ^ memop) & MO_BSWAP) { + tcg_gen_bswap64_i64(y, y); + } + + plugin_gen_mem_callbacks(addr, make_memop_idx(memop, idx), + QEMU_PLUGIN_MEM_R); +} + +void tcg_gen_qemu_st_i128(TCGv_i128 val, TCGv addr, TCGArg idx, MemOp memop) +{ + MemOp mop[2]; + TCGv addr_p8; + TCGv_i64 x, y; + + canonicalize_memop_i128_as_i64(mop, memop); + + tcg_gen_req_mo(TCG_MO_ST_LD | TCG_MO_ST_ST); + addr = plugin_prep_mem_callbacks(addr); + + /* TODO: respect atomicity of the operation. */ + /* TODO: allow the tcg backend to see the whole operation. */ + + if ((memop & MO_BSWAP) == MO_LE) { + x = TCGV128_LOW(val); + y = TCGV128_HIGH(val); + } else { + x = TCGV128_HIGH(val); + y = TCGV128_LOW(val); + } + + addr_p8 = tcg_temp_new(); + if ((mop[0] ^ memop) & MO_BSWAP) { + TCGv_i64 t = tcg_temp_new_i64(); + + tcg_gen_bswap64_i64(t, x); + gen_ldst_i64(INDEX_op_qemu_st_i64, t, addr, mop[0], idx); + tcg_gen_bswap64_i64(t, y); + tcg_gen_addi_tl(addr_p8, addr, 8); + gen_ldst_i64(INDEX_op_qemu_st_i64, t, addr_p8, mop[1], idx); + tcg_temp_free_i64(t); + } else { + gen_ldst_i64(INDEX_op_qemu_st_i64, x, addr, mop[0], idx); + tcg_gen_addi_tl(addr_p8, addr, 8); + gen_ldst_i64(INDEX_op_qemu_st_i64, y, addr_p8, mop[1], idx); + } + tcg_temp_free(addr_p8); + + plugin_gen_mem_callbacks(addr, make_memop_idx(memop, idx), + QEMU_PLUGIN_MEM_W); +} + static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, MemOp opc) { switch (opc & MO_SSIZE) { From 123ae5683c9e7815857304fd2f21664621c90a13 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Nov 2022 00:23:44 +1100 Subject: [PATCH 487/814] tcg: Add tcg_gen_{non}atomic_cmpxchg_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow targets to avoid rolling their own. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/atomic_common.c.inc | 45 +++++++++++++++++++ accel/tcg/tcg-runtime.h | 11 +++++ include/tcg/tcg-op.h | 5 +++ tcg/tcg-op.c | 85 +++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) diff --git a/accel/tcg/atomic_common.c.inc b/accel/tcg/atomic_common.c.inc index 6602d7689f..8f2ce43ee6 100644 --- a/accel/tcg/atomic_common.c.inc +++ b/accel/tcg/atomic_common.c.inc @@ -55,8 +55,53 @@ CMPXCHG_HELPER(cmpxchgq_be, uint64_t) CMPXCHG_HELPER(cmpxchgq_le, uint64_t) #endif +#ifdef CONFIG_CMPXCHG128 +CMPXCHG_HELPER(cmpxchgo_be, Int128) +CMPXCHG_HELPER(cmpxchgo_le, Int128) +#endif + #undef CMPXCHG_HELPER +Int128 HELPER(nonatomic_cmpxchgo_be)(CPUArchState *env, target_ulong addr, + Int128 cmpv, Int128 newv, uint32_t oi) +{ +#if TCG_TARGET_REG_BITS == 32 + uintptr_t ra = GETPC(); + Int128 oldv; + + oldv = cpu_ld16_be_mmu(env, addr, oi, ra); + if (int128_eq(oldv, cmpv)) { + cpu_st16_be_mmu(env, addr, newv, oi, ra); + } else { + /* Even with comparison failure, still need a write cycle. */ + probe_write(env, addr, 16, get_mmuidx(oi), ra); + } + return oldv; +#else + g_assert_not_reached(); +#endif +} + +Int128 HELPER(nonatomic_cmpxchgo_le)(CPUArchState *env, target_ulong addr, + Int128 cmpv, Int128 newv, uint32_t oi) +{ +#if TCG_TARGET_REG_BITS == 32 + uintptr_t ra = GETPC(); + Int128 oldv; + + oldv = cpu_ld16_le_mmu(env, addr, oi, ra); + if (int128_eq(oldv, cmpv)) { + cpu_st16_le_mmu(env, addr, newv, oi, ra); + } else { + /* Even with comparison failure, still need a write cycle. */ + probe_write(env, addr, 16, get_mmuidx(oi), ra); + } + return oldv; +#else + g_assert_not_reached(); +#endif +} + #define ATOMIC_HELPER(OP, TYPE) \ TYPE HELPER(glue(atomic_,OP))(CPUArchState *env, target_ulong addr, \ TYPE val, uint32_t oi) \ diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 37cbd722bf..e141a6ab24 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -55,6 +55,17 @@ DEF_HELPER_FLAGS_5(atomic_cmpxchgq_be, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_5(atomic_cmpxchgq_le, TCG_CALL_NO_WG, i64, env, tl, i64, i64, i32) #endif +#ifdef CONFIG_CMPXCHG128 +DEF_HELPER_FLAGS_5(atomic_cmpxchgo_be, TCG_CALL_NO_WG, + i128, env, tl, i128, i128, i32) +DEF_HELPER_FLAGS_5(atomic_cmpxchgo_le, TCG_CALL_NO_WG, + i128, env, tl, i128, i128, i32) +#endif + +DEF_HELPER_FLAGS_5(nonatomic_cmpxchgo_be, TCG_CALL_NO_WG, + i128, env, tl, i128, i128, i32) +DEF_HELPER_FLAGS_5(nonatomic_cmpxchgo_le, TCG_CALL_NO_WG, + i128, env, tl, i128, i128, i32) #ifdef CONFIG_ATOMIC64 #define GEN_ATOMIC_HELPERS(NAME) \ diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index e5f5b63c37..31bf3d287e 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -907,6 +907,11 @@ void tcg_gen_atomic_cmpxchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGv_i32, TCGArg, MemOp); void tcg_gen_atomic_cmpxchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGv_i64, TCGArg, MemOp); +void tcg_gen_atomic_cmpxchg_i128(TCGv_i128, TCGv, TCGv_i128, TCGv_i128, + TCGArg, MemOp); + +void tcg_gen_nonatomic_cmpxchg_i128(TCGv_i128, TCGv, TCGv_i128, TCGv_i128, + TCGArg, MemOp); void tcg_gen_atomic_xchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGArg, MemOp); void tcg_gen_atomic_xchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGArg, MemOp); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 33ef325f6e..5811ecd3e7 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -3295,6 +3295,8 @@ typedef void (*gen_atomic_cx_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32, TCGv_i32); typedef void (*gen_atomic_cx_i64)(TCGv_i64, TCGv_env, TCGv, TCGv_i64, TCGv_i64, TCGv_i32); +typedef void (*gen_atomic_cx_i128)(TCGv_i128, TCGv_env, TCGv, + TCGv_i128, TCGv_i128, TCGv_i32); typedef void (*gen_atomic_op_i32)(TCGv_i32, TCGv_env, TCGv, TCGv_i32, TCGv_i32); typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, @@ -3305,6 +3307,11 @@ typedef void (*gen_atomic_op_i64)(TCGv_i64, TCGv_env, TCGv, #else # define WITH_ATOMIC64(X) #endif +#ifdef CONFIG_CMPXCHG128 +# define WITH_ATOMIC128(X) X, +#else +# define WITH_ATOMIC128(X) +#endif static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = { [MO_8] = gen_helper_atomic_cmpxchgb, @@ -3314,6 +3321,8 @@ static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = { [MO_32 | MO_BE] = gen_helper_atomic_cmpxchgl_be, WITH_ATOMIC64([MO_64 | MO_LE] = gen_helper_atomic_cmpxchgq_le) WITH_ATOMIC64([MO_64 | MO_BE] = gen_helper_atomic_cmpxchgq_be) + WITH_ATOMIC128([MO_128 | MO_LE] = gen_helper_atomic_cmpxchgo_le) + WITH_ATOMIC128([MO_128 | MO_BE] = gen_helper_atomic_cmpxchgo_be) }; void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, @@ -3412,6 +3421,82 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, } } +void tcg_gen_nonatomic_cmpxchg_i128(TCGv_i128 retv, TCGv addr, TCGv_i128 cmpv, + TCGv_i128 newv, TCGArg idx, MemOp memop) +{ + if (TCG_TARGET_REG_BITS == 32) { + /* Inline expansion below is simply too large for 32-bit hosts. */ + gen_atomic_cx_i128 gen = ((memop & MO_BSWAP) == MO_LE + ? gen_helper_nonatomic_cmpxchgo_le + : gen_helper_nonatomic_cmpxchgo_be); + MemOpIdx oi = make_memop_idx(memop, idx); + + tcg_debug_assert((memop & MO_SIZE) == MO_128); + tcg_debug_assert((memop & MO_SIGN) == 0); + + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); + } else { + TCGv_i128 oldv = tcg_temp_new_i128(); + TCGv_i128 tmpv = tcg_temp_new_i128(); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 z = tcg_constant_i64(0); + + tcg_gen_qemu_ld_i128(oldv, addr, idx, memop); + + /* Compare i128 */ + tcg_gen_xor_i64(t0, TCGV128_LOW(oldv), TCGV128_LOW(cmpv)); + tcg_gen_xor_i64(t1, TCGV128_HIGH(oldv), TCGV128_HIGH(cmpv)); + tcg_gen_or_i64(t0, t0, t1); + + /* tmpv = equal ? newv : oldv */ + tcg_gen_movcond_i64(TCG_COND_EQ, TCGV128_LOW(tmpv), t0, z, + TCGV128_LOW(newv), TCGV128_LOW(oldv)); + tcg_gen_movcond_i64(TCG_COND_EQ, TCGV128_HIGH(tmpv), t0, z, + TCGV128_HIGH(newv), TCGV128_HIGH(oldv)); + + /* Unconditional writeback. */ + tcg_gen_qemu_st_i128(tmpv, addr, idx, memop); + tcg_gen_mov_i128(retv, oldv); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i128(tmpv); + tcg_temp_free_i128(oldv); + } +} + +void tcg_gen_atomic_cmpxchg_i128(TCGv_i128 retv, TCGv addr, TCGv_i128 cmpv, + TCGv_i128 newv, TCGArg idx, MemOp memop) +{ + gen_atomic_cx_i128 gen; + + if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { + tcg_gen_nonatomic_cmpxchg_i128(retv, addr, cmpv, newv, idx, memop); + return; + } + + tcg_debug_assert((memop & MO_SIZE) == MO_128); + tcg_debug_assert((memop & MO_SIGN) == 0); + gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; + + if (gen) { + MemOpIdx oi = make_memop_idx(memop, idx); + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); + return; + } + + gen_helper_exit_atomic(cpu_env); + + /* + * Produce a result for a well-formed opcode stream. This satisfies + * liveness for set before used, which happens before this dead code + * is removed. + */ + tcg_gen_movi_i64(TCGV128_LOW(retv), 0); + tcg_gen_movi_i64(TCGV128_HIGH(retv), 0); +} + static void do_nonatomic_op_i32(TCGv_i32 ret, TCGv addr, TCGv_i32 val, TCGArg idx, MemOp memop, bool new_val, void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32)) From d1beee4da1dbbc0ce1bc42b38752366eed4babec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 10 Nov 2022 16:07:04 +1000 Subject: [PATCH 488/814] tcg: Split out tcg_gen_nonatomic_cmpxchg_i{32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normally this is automatically handled by the CF_PARALLEL checks with in tcg_gen_atomic_cmpxchg_i{32,64}, but x86 has a special case of !PREFIX_LOCK where it always wants the non-atomic version. Split these out so that x86 does not have to roll its own. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 4 ++ tcg/tcg-op.c | 154 +++++++++++++++++++++++++++---------------- 2 files changed, 101 insertions(+), 57 deletions(-) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 31bf3d287e..839d91c0c7 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -910,6 +910,10 @@ void tcg_gen_atomic_cmpxchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGv_i64, void tcg_gen_atomic_cmpxchg_i128(TCGv_i128, TCGv, TCGv_i128, TCGv_i128, TCGArg, MemOp); +void tcg_gen_nonatomic_cmpxchg_i32(TCGv_i32, TCGv, TCGv_i32, TCGv_i32, + TCGArg, MemOp); +void tcg_gen_nonatomic_cmpxchg_i64(TCGv_i64, TCGv, TCGv_i64, TCGv_i64, + TCGArg, MemOp); void tcg_gen_nonatomic_cmpxchg_i128(TCGv_i128, TCGv, TCGv_i128, TCGv_i128, TCGArg, MemOp); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 5811ecd3e7..c581ae77c4 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -3325,82 +3325,122 @@ static void * const table_cmpxchg[(MO_SIZE | MO_BSWAP) + 1] = { WITH_ATOMIC128([MO_128 | MO_BE] = gen_helper_atomic_cmpxchgo_be) }; +void tcg_gen_nonatomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, + TCGv_i32 newv, TCGArg idx, MemOp memop) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE); + + tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); + tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1); + tcg_gen_qemu_st_i32(t2, addr, idx, memop); + tcg_temp_free_i32(t2); + + if (memop & MO_SIGN) { + tcg_gen_ext_i32(retv, t1, memop); + } else { + tcg_gen_mov_i32(retv, t1); + } + tcg_temp_free_i32(t1); +} + void tcg_gen_atomic_cmpxchg_i32(TCGv_i32 retv, TCGv addr, TCGv_i32 cmpv, TCGv_i32 newv, TCGArg idx, MemOp memop) { - memop = tcg_canonicalize_memop(memop, 0, 0); + gen_atomic_cx_i32 gen; + MemOpIdx oi; if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - tcg_gen_ext_i32(t2, cmpv, memop & MO_SIZE); - - tcg_gen_qemu_ld_i32(t1, addr, idx, memop & ~MO_SIGN); - tcg_gen_movcond_i32(TCG_COND_EQ, t2, t1, t2, newv, t1); - tcg_gen_qemu_st_i32(t2, addr, idx, memop); - tcg_temp_free_i32(t2); - - if (memop & MO_SIGN) { - tcg_gen_ext_i32(retv, t1, memop); - } else { - tcg_gen_mov_i32(retv, t1); - } - tcg_temp_free_i32(t1); - } else { - gen_atomic_cx_i32 gen; - MemOpIdx oi; - - gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; - tcg_debug_assert(gen != NULL); - - oi = make_memop_idx(memop & ~MO_SIGN, idx); - gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); - - if (memop & MO_SIGN) { - tcg_gen_ext_i32(retv, retv, memop); - } + tcg_gen_nonatomic_cmpxchg_i32(retv, addr, cmpv, newv, idx, memop); + return; } + + memop = tcg_canonicalize_memop(memop, 0, 0); + gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; + tcg_debug_assert(gen != NULL); + + oi = make_memop_idx(memop & ~MO_SIGN, idx); + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); + + if (memop & MO_SIGN) { + tcg_gen_ext_i32(retv, retv, memop); + } +} + +void tcg_gen_nonatomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, + TCGv_i64 newv, TCGArg idx, MemOp memop) +{ + TCGv_i64 t1, t2; + + if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) { + tcg_gen_nonatomic_cmpxchg_i32(TCGV_LOW(retv), addr, TCGV_LOW(cmpv), + TCGV_LOW(newv), idx, memop); + if (memop & MO_SIGN) { + tcg_gen_sari_i32(TCGV_HIGH(retv), TCGV_LOW(retv), 31); + } else { + tcg_gen_movi_i32(TCGV_HIGH(retv), 0); + } + return; + } + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + + tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE); + + tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); + tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1); + tcg_gen_qemu_st_i64(t2, addr, idx, memop); + tcg_temp_free_i64(t2); + + if (memop & MO_SIGN) { + tcg_gen_ext_i64(retv, t1, memop); + } else { + tcg_gen_mov_i64(retv, t1); + } + tcg_temp_free_i64(t1); } void tcg_gen_atomic_cmpxchg_i64(TCGv_i64 retv, TCGv addr, TCGv_i64 cmpv, TCGv_i64 newv, TCGArg idx, MemOp memop) { - memop = tcg_canonicalize_memop(memop, 1, 0); - if (!(tcg_ctx->gen_tb->cflags & CF_PARALLEL)) { - TCGv_i64 t1 = tcg_temp_new_i64(); - TCGv_i64 t2 = tcg_temp_new_i64(); + tcg_gen_nonatomic_cmpxchg_i64(retv, addr, cmpv, newv, idx, memop); + return; + } - tcg_gen_ext_i64(t2, cmpv, memop & MO_SIZE); - - tcg_gen_qemu_ld_i64(t1, addr, idx, memop & ~MO_SIGN); - tcg_gen_movcond_i64(TCG_COND_EQ, t2, t1, t2, newv, t1); - tcg_gen_qemu_st_i64(t2, addr, idx, memop); - tcg_temp_free_i64(t2); - - if (memop & MO_SIGN) { - tcg_gen_ext_i64(retv, t1, memop); - } else { - tcg_gen_mov_i64(retv, t1); - } - tcg_temp_free_i64(t1); - } else if ((memop & MO_SIZE) == MO_64) { -#ifdef CONFIG_ATOMIC64 + if ((memop & MO_SIZE) == MO_64) { gen_atomic_cx_i64 gen; - MemOpIdx oi; + memop = tcg_canonicalize_memop(memop, 1, 0); gen = table_cmpxchg[memop & (MO_SIZE | MO_BSWAP)]; - tcg_debug_assert(gen != NULL); + if (gen) { + MemOpIdx oi = make_memop_idx(memop, idx); + gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); + return; + } - oi = make_memop_idx(memop, idx); - gen(retv, cpu_env, addr, cmpv, newv, tcg_constant_i32(oi)); -#else gen_helper_exit_atomic(cpu_env); - /* Produce a result, so that we have a well-formed opcode stream - with respect to uses of the result in the (dead) code following. */ + + /* + * Produce a result for a well-formed opcode stream. This satisfies + * liveness for set before used, which happens before this dead code + * is removed. + */ tcg_gen_movi_i64(retv, 0); -#endif /* CONFIG_ATOMIC64 */ + return; + } + + if (TCG_TARGET_REG_BITS == 32) { + tcg_gen_atomic_cmpxchg_i32(TCGV_LOW(retv), addr, TCGV_LOW(cmpv), + TCGV_LOW(newv), idx, memop); + if (memop & MO_SIGN) { + tcg_gen_sari_i32(TCGV_HIGH(retv), TCGV_LOW(retv), 31); + } else { + tcg_gen_movi_i32(TCGV_HIGH(retv), 0); + } } else { TCGv_i32 c32 = tcg_temp_new_i32(); TCGv_i32 n32 = tcg_temp_new_i32(); From 546789c7df8866c55cae8d3195e8e58328a35d51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 12 Nov 2022 14:25:54 +1000 Subject: [PATCH 489/814] target/arm: Use tcg_gen_atomic_cmpxchg_i128 for STXP Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20221112042555.2622152-2-richard.henderson@linaro.org> --- target/arm/helper-a64.c | 104 ------------------------------------- target/arm/helper-a64.h | 6 --- target/arm/translate-a64.c | 60 ++++++++++++--------- 3 files changed, 35 insertions(+), 135 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 77a8502b6b..7dbdb2c233 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -505,110 +505,6 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes) return crc32c(acc, buf, bytes) ^ 0xffffffff; } -uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr, - uint64_t new_lo, uint64_t new_hi) -{ - Int128 cmpv = int128_make128(env->exclusive_val, env->exclusive_high); - Int128 newv = int128_make128(new_lo, new_hi); - Int128 oldv; - uintptr_t ra = GETPC(); - uint64_t o0, o1; - bool success; - int mem_idx = cpu_mmu_index(env, false); - MemOpIdx oi0 = make_memop_idx(MO_LEUQ | MO_ALIGN_16, mem_idx); - MemOpIdx oi1 = make_memop_idx(MO_LEUQ, mem_idx); - - o0 = cpu_ldq_le_mmu(env, addr + 0, oi0, ra); - o1 = cpu_ldq_le_mmu(env, addr + 8, oi1, ra); - oldv = int128_make128(o0, o1); - - success = int128_eq(oldv, cmpv); - if (success) { - cpu_stq_le_mmu(env, addr + 0, int128_getlo(newv), oi1, ra); - cpu_stq_le_mmu(env, addr + 8, int128_gethi(newv), oi1, ra); - } - - return !success; -} - -uint64_t HELPER(paired_cmpxchg64_le_parallel)(CPUARMState *env, uint64_t addr, - uint64_t new_lo, uint64_t new_hi) -{ - Int128 oldv, cmpv, newv; - uintptr_t ra = GETPC(); - bool success; - int mem_idx; - MemOpIdx oi; - - assert(HAVE_CMPXCHG128); - - mem_idx = cpu_mmu_index(env, false); - oi = make_memop_idx(MO_LE | MO_128 | MO_ALIGN, mem_idx); - - cmpv = int128_make128(env->exclusive_val, env->exclusive_high); - newv = int128_make128(new_lo, new_hi); - oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); - - success = int128_eq(oldv, cmpv); - return !success; -} - -uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr, - uint64_t new_lo, uint64_t new_hi) -{ - /* - * High and low need to be switched here because this is not actually a - * 128bit store but two doublewords stored consecutively - */ - Int128 cmpv = int128_make128(env->exclusive_high, env->exclusive_val); - Int128 newv = int128_make128(new_hi, new_lo); - Int128 oldv; - uintptr_t ra = GETPC(); - uint64_t o0, o1; - bool success; - int mem_idx = cpu_mmu_index(env, false); - MemOpIdx oi0 = make_memop_idx(MO_BEUQ | MO_ALIGN_16, mem_idx); - MemOpIdx oi1 = make_memop_idx(MO_BEUQ, mem_idx); - - o1 = cpu_ldq_be_mmu(env, addr + 0, oi0, ra); - o0 = cpu_ldq_be_mmu(env, addr + 8, oi1, ra); - oldv = int128_make128(o0, o1); - - success = int128_eq(oldv, cmpv); - if (success) { - cpu_stq_be_mmu(env, addr + 0, int128_gethi(newv), oi1, ra); - cpu_stq_be_mmu(env, addr + 8, int128_getlo(newv), oi1, ra); - } - - return !success; -} - -uint64_t HELPER(paired_cmpxchg64_be_parallel)(CPUARMState *env, uint64_t addr, - uint64_t new_lo, uint64_t new_hi) -{ - Int128 oldv, cmpv, newv; - uintptr_t ra = GETPC(); - bool success; - int mem_idx; - MemOpIdx oi; - - assert(HAVE_CMPXCHG128); - - mem_idx = cpu_mmu_index(env, false); - oi = make_memop_idx(MO_BE | MO_128 | MO_ALIGN, mem_idx); - - /* - * High and low need to be switched here because this is not actually a - * 128bit store but two doublewords stored consecutively - */ - cmpv = int128_make128(env->exclusive_high, env->exclusive_val); - newv = int128_make128(new_hi, new_lo); - oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); - - success = int128_eq(oldv, cmpv); - return !success; -} - /* Writes back the old data into Rs. */ void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr, uint64_t new_lo, uint64_t new_hi) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 7b706571bb..94065d1917 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -50,12 +50,6 @@ DEF_HELPER_FLAGS_2(frecpx_f16, TCG_CALL_NO_RWG, f16, f16, ptr) DEF_HELPER_FLAGS_2(fcvtx_f64_to_f32, TCG_CALL_NO_RWG, f32, f64, env) DEF_HELPER_FLAGS_3(crc32_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) DEF_HELPER_FLAGS_3(crc32c_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) -DEF_HELPER_FLAGS_4(paired_cmpxchg64_le, TCG_CALL_NO_WG, i64, env, i64, i64, i64) -DEF_HELPER_FLAGS_4(paired_cmpxchg64_le_parallel, TCG_CALL_NO_WG, - i64, env, i64, i64, i64) -DEF_HELPER_FLAGS_4(paired_cmpxchg64_be, TCG_CALL_NO_WG, i64, env, i64, i64, i64) -DEF_HELPER_FLAGS_4(paired_cmpxchg64_be_parallel, TCG_CALL_NO_WG, - i64, env, i64, i64, i64) DEF_HELPER_5(casp_le_parallel, void, env, i32, i64, i64, i64) DEF_HELPER_5(casp_be_parallel, void, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(advsimd_maxh, TCG_CALL_NO_RWG, f16, f16, f16, ptr) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index bbfadb7c2e..951b64c9b1 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2601,32 +2601,42 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, get_mem_index(s), MO_64 | MO_ALIGN | s->be_data); tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val); - } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { - if (!HAVE_CMPXCHG128) { - gen_helper_exit_atomic(cpu_env); - /* - * Produce a result so we have a well-formed opcode - * stream when the following (dead) code uses 'tmp'. - * TCG will remove the dead ops for us. - */ - tcg_gen_movi_i64(tmp, 0); - } else if (s->be_data == MO_LE) { - gen_helper_paired_cmpxchg64_le_parallel(tmp, cpu_env, - cpu_exclusive_addr, - cpu_reg(s, rt), - cpu_reg(s, rt2)); - } else { - gen_helper_paired_cmpxchg64_be_parallel(tmp, cpu_env, - cpu_exclusive_addr, - cpu_reg(s, rt), - cpu_reg(s, rt2)); - } - } else if (s->be_data == MO_LE) { - gen_helper_paired_cmpxchg64_le(tmp, cpu_env, cpu_exclusive_addr, - cpu_reg(s, rt), cpu_reg(s, rt2)); } else { - gen_helper_paired_cmpxchg64_be(tmp, cpu_env, cpu_exclusive_addr, - cpu_reg(s, rt), cpu_reg(s, rt2)); + TCGv_i128 t16 = tcg_temp_new_i128(); + TCGv_i128 c16 = tcg_temp_new_i128(); + TCGv_i64 a, b; + + if (s->be_data == MO_LE) { + tcg_gen_concat_i64_i128(t16, cpu_reg(s, rt), cpu_reg(s, rt2)); + tcg_gen_concat_i64_i128(c16, cpu_exclusive_val, + cpu_exclusive_high); + } else { + tcg_gen_concat_i64_i128(t16, cpu_reg(s, rt2), cpu_reg(s, rt)); + tcg_gen_concat_i64_i128(c16, cpu_exclusive_high, + cpu_exclusive_val); + } + + tcg_gen_atomic_cmpxchg_i128(t16, cpu_exclusive_addr, c16, t16, + get_mem_index(s), + MO_128 | MO_ALIGN | s->be_data); + tcg_temp_free_i128(c16); + + a = tcg_temp_new_i64(); + b = tcg_temp_new_i64(); + if (s->be_data == MO_LE) { + tcg_gen_extr_i128_i64(a, b, t16); + } else { + tcg_gen_extr_i128_i64(b, a, t16); + } + + tcg_gen_xor_i64(a, a, cpu_exclusive_val); + tcg_gen_xor_i64(b, b, cpu_exclusive_high); + tcg_gen_or_i64(tmp, a, b); + tcg_temp_free_i64(a); + tcg_temp_free_i64(b); + tcg_temp_free_i128(t16); + + tcg_gen_setcondi_i64(TCG_COND_NE, tmp, tmp, 0); } } else { tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr, cpu_exclusive_val, From 9c32396debee91a87867abc562bb8e2b458c958a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 12 Nov 2022 14:25:55 +1000 Subject: [PATCH 490/814] target/arm: Use tcg_gen_atomic_cmpxchg_i128 for CASP Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20221112042555.2622152-3-richard.henderson@linaro.org> --- target/arm/helper-a64.c | 43 --------------------------- target/arm/helper-a64.h | 2 -- target/arm/translate-a64.c | 61 +++++++++++--------------------------- 3 files changed, 18 insertions(+), 88 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 7dbdb2c233..0972a4bdd0 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -505,49 +505,6 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes) return crc32c(acc, buf, bytes) ^ 0xffffffff; } -/* Writes back the old data into Rs. */ -void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr, - uint64_t new_lo, uint64_t new_hi) -{ - Int128 oldv, cmpv, newv; - uintptr_t ra = GETPC(); - int mem_idx; - MemOpIdx oi; - - assert(HAVE_CMPXCHG128); - - mem_idx = cpu_mmu_index(env, false); - oi = make_memop_idx(MO_LE | MO_128 | MO_ALIGN, mem_idx); - - cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]); - newv = int128_make128(new_lo, new_hi); - oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra); - - env->xregs[rs] = int128_getlo(oldv); - env->xregs[rs + 1] = int128_gethi(oldv); -} - -void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr, - uint64_t new_hi, uint64_t new_lo) -{ - Int128 oldv, cmpv, newv; - uintptr_t ra = GETPC(); - int mem_idx; - MemOpIdx oi; - - assert(HAVE_CMPXCHG128); - - mem_idx = cpu_mmu_index(env, false); - oi = make_memop_idx(MO_LE | MO_128 | MO_ALIGN, mem_idx); - - cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]); - newv = int128_make128(new_lo, new_hi); - oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); - - env->xregs[rs + 1] = int128_getlo(oldv); - env->xregs[rs] = int128_gethi(oldv); -} - /* * AdvSIMD half-precision */ diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 94065d1917..ff56807247 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -50,8 +50,6 @@ DEF_HELPER_FLAGS_2(frecpx_f16, TCG_CALL_NO_RWG, f16, f16, ptr) DEF_HELPER_FLAGS_2(fcvtx_f64_to_f32, TCG_CALL_NO_RWG, f32, f64, env) DEF_HELPER_FLAGS_3(crc32_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) DEF_HELPER_FLAGS_3(crc32c_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32) -DEF_HELPER_5(casp_le_parallel, void, env, i32, i64, i64, i64) -DEF_HELPER_5(casp_be_parallel, void, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(advsimd_maxh, TCG_CALL_NO_RWG, f16, f16, f16, ptr) DEF_HELPER_FLAGS_3(advsimd_minh, TCG_CALL_NO_RWG, f16, f16, f16, ptr) DEF_HELPER_FLAGS_3(advsimd_maxnumh, TCG_CALL_NO_RWG, f16, f16, f16, ptr) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 951b64c9b1..da9f877476 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2709,53 +2709,28 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, tcg_gen_extr32_i64(s2, s1, cmp); } tcg_temp_free_i64(cmp); - } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { - if (HAVE_CMPXCHG128) { - TCGv_i32 tcg_rs = tcg_constant_i32(rs); - if (s->be_data == MO_LE) { - gen_helper_casp_le_parallel(cpu_env, tcg_rs, - clean_addr, t1, t2); - } else { - gen_helper_casp_be_parallel(cpu_env, tcg_rs, - clean_addr, t1, t2); - } - } else { - gen_helper_exit_atomic(cpu_env); - s->base.is_jmp = DISAS_NORETURN; - } } else { - TCGv_i64 d1 = tcg_temp_new_i64(); - TCGv_i64 d2 = tcg_temp_new_i64(); - TCGv_i64 a2 = tcg_temp_new_i64(); - TCGv_i64 c1 = tcg_temp_new_i64(); - TCGv_i64 c2 = tcg_temp_new_i64(); - TCGv_i64 zero = tcg_constant_i64(0); + TCGv_i128 cmp = tcg_temp_new_i128(); + TCGv_i128 val = tcg_temp_new_i128(); - /* Load the two words, in memory order. */ - tcg_gen_qemu_ld_i64(d1, clean_addr, memidx, - MO_64 | MO_ALIGN_16 | s->be_data); - tcg_gen_addi_i64(a2, clean_addr, 8); - tcg_gen_qemu_ld_i64(d2, a2, memidx, MO_64 | s->be_data); + if (s->be_data == MO_LE) { + tcg_gen_concat_i64_i128(val, t1, t2); + tcg_gen_concat_i64_i128(cmp, s1, s2); + } else { + tcg_gen_concat_i64_i128(val, t2, t1); + tcg_gen_concat_i64_i128(cmp, s2, s1); + } - /* Compare the two words, also in memory order. */ - tcg_gen_setcond_i64(TCG_COND_EQ, c1, d1, s1); - tcg_gen_setcond_i64(TCG_COND_EQ, c2, d2, s2); - tcg_gen_and_i64(c2, c2, c1); + tcg_gen_atomic_cmpxchg_i128(cmp, clean_addr, cmp, val, memidx, + MO_128 | MO_ALIGN | s->be_data); + tcg_temp_free_i128(val); - /* If compare equal, write back new data, else write back old data. */ - tcg_gen_movcond_i64(TCG_COND_NE, c1, c2, zero, t1, d1); - tcg_gen_movcond_i64(TCG_COND_NE, c2, c2, zero, t2, d2); - tcg_gen_qemu_st_i64(c1, clean_addr, memidx, MO_64 | s->be_data); - tcg_gen_qemu_st_i64(c2, a2, memidx, MO_64 | s->be_data); - tcg_temp_free_i64(a2); - tcg_temp_free_i64(c1); - tcg_temp_free_i64(c2); - - /* Write back the data from memory to Rs. */ - tcg_gen_mov_i64(s1, d1); - tcg_gen_mov_i64(s2, d2); - tcg_temp_free_i64(d1); - tcg_temp_free_i64(d2); + if (s->be_data == MO_LE) { + tcg_gen_extr_i128_i64(s1, s2, cmp); + } else { + tcg_gen_extr_i128_i64(s2, s1, cmp); + } + tcg_temp_free_i128(cmp); } } From 894448ae7dce4269c4b3c152a7091520317ea397 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 12 Nov 2022 16:11:22 +1000 Subject: [PATCH 491/814] target/ppc: Use tcg_gen_atomic_cmpxchg_i128 for STQCX Note that the previous direct reference to reserve_val, - tcg_gen_ld_i64(t1, cpu_env, (ctx->le_mode - ? offsetof(CPUPPCState, reserve_val2) - : offsetof(CPUPPCState, reserve_val))); was incorrect because all references should have gone through cpu_reserve_val. Create a cpu_reserve_val2 tcg temp to fix this. Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Message-Id: <20221112061122.2720163-2-richard.henderson@linaro.org> --- target/ppc/helper.h | 2 - target/ppc/mem_helper.c | 44 ----------------- target/ppc/translate.c | 102 ++++++++++++++++++---------------------- 3 files changed, 47 insertions(+), 101 deletions(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 8dd22a35e4..0beaca5c7a 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -818,6 +818,4 @@ DEF_HELPER_FLAGS_5(stq_le_parallel, TCG_CALL_NO_WG, void, env, tl, i64, i64, i32) DEF_HELPER_FLAGS_5(stq_be_parallel, TCG_CALL_NO_WG, void, env, tl, i64, i64, i32) -DEF_HELPER_5(stqcx_le_parallel, i32, env, tl, i64, i64, i32) -DEF_HELPER_5(stqcx_be_parallel, i32, env, tl, i64, i64, i32) #endif diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index d1163f316c..1578887a8f 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -413,50 +413,6 @@ void helper_stq_be_parallel(CPUPPCState *env, target_ulong addr, val = int128_make128(lo, hi); cpu_atomic_sto_be_mmu(env, addr, val, opidx, GETPC()); } - -uint32_t helper_stqcx_le_parallel(CPUPPCState *env, target_ulong addr, - uint64_t new_lo, uint64_t new_hi, - uint32_t opidx) -{ - bool success = false; - - /* We will have raised EXCP_ATOMIC from the translator. */ - assert(HAVE_CMPXCHG128); - - if (likely(addr == env->reserve_addr)) { - Int128 oldv, cmpv, newv; - - cmpv = int128_make128(env->reserve_val2, env->reserve_val); - newv = int128_make128(new_lo, new_hi); - oldv = cpu_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, - opidx, GETPC()); - success = int128_eq(oldv, cmpv); - } - env->reserve_addr = -1; - return env->so + success * CRF_EQ_BIT; -} - -uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr, - uint64_t new_lo, uint64_t new_hi, - uint32_t opidx) -{ - bool success = false; - - /* We will have raised EXCP_ATOMIC from the translator. */ - assert(HAVE_CMPXCHG128); - - if (likely(addr == env->reserve_addr)) { - Int128 oldv, cmpv, newv; - - cmpv = int128_make128(env->reserve_val2, env->reserve_val); - newv = int128_make128(new_lo, new_hi); - oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, - opidx, GETPC()); - success = int128_eq(oldv, cmpv); - } - env->reserve_addr = -1; - return env->so + success * CRF_EQ_BIT; -} #endif /*****************************************************************************/ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index edb3daa9b5..1c17d5a558 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -72,6 +72,7 @@ static TCGv cpu_cfar; static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca, cpu_ov32, cpu_ca32; static TCGv cpu_reserve; static TCGv cpu_reserve_val; +static TCGv cpu_reserve_val2; static TCGv cpu_fpscr; static TCGv_i32 cpu_access_type; @@ -141,8 +142,11 @@ void ppc_translate_init(void) offsetof(CPUPPCState, reserve_addr), "reserve_addr"); cpu_reserve_val = tcg_global_mem_new(cpu_env, - offsetof(CPUPPCState, reserve_val), - "reserve_val"); + offsetof(CPUPPCState, reserve_val), + "reserve_val"); + cpu_reserve_val2 = tcg_global_mem_new(cpu_env, + offsetof(CPUPPCState, reserve_val2), + "reserve_val2"); cpu_fpscr = tcg_global_mem_new(cpu_env, offsetof(CPUPPCState, fpscr), "fpscr"); @@ -3998,78 +4002,66 @@ static void gen_lqarx(DisasContext *ctx) /* stqcx. */ static void gen_stqcx_(DisasContext *ctx) { + TCGLabel *lab_fail, *lab_over; int rs = rS(ctx->opcode); - TCGv EA, hi, lo; + TCGv EA, t0, t1; + TCGv_i128 cmp, val; if (unlikely(rs & 1)) { gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } + lab_fail = gen_new_label(); + lab_over = gen_new_label(); + gen_set_access_type(ctx, ACCESS_RES); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); + tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, lab_fail); + tcg_temp_free(EA); + + cmp = tcg_temp_new_i128(); + val = tcg_temp_new_i128(); + + tcg_gen_concat_i64_i128(cmp, cpu_reserve_val2, cpu_reserve_val); + /* Note that the low part is always in RS+1, even in LE mode. */ - lo = cpu_gpr[rs + 1]; - hi = cpu_gpr[rs]; + tcg_gen_concat_i64_i128(val, cpu_gpr[rs + 1], cpu_gpr[rs]); - if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { - if (HAVE_CMPXCHG128) { - TCGv_i32 oi = tcg_const_i32(DEF_MEMOP(MO_128) | MO_ALIGN); - if (ctx->le_mode) { - gen_helper_stqcx_le_parallel(cpu_crf[0], cpu_env, - EA, lo, hi, oi); - } else { - gen_helper_stqcx_be_parallel(cpu_crf[0], cpu_env, - EA, lo, hi, oi); - } - tcg_temp_free_i32(oi); - } else { - /* Restart with exclusive lock. */ - gen_helper_exit_atomic(cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; - } - tcg_temp_free(EA); - } else { - TCGLabel *lab_fail = gen_new_label(); - TCGLabel *lab_over = gen_new_label(); - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_atomic_cmpxchg_i128(val, cpu_reserve, cmp, val, ctx->mem_idx, + DEF_MEMOP(MO_128 | MO_ALIGN)); + tcg_temp_free_i128(cmp); - tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, lab_fail); - tcg_temp_free(EA); + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + tcg_gen_extr_i128_i64(t1, t0, val); + tcg_temp_free_i128(val); - gen_qemu_ld64_i64(ctx, t0, cpu_reserve); - tcg_gen_ld_i64(t1, cpu_env, (ctx->le_mode - ? offsetof(CPUPPCState, reserve_val2) - : offsetof(CPUPPCState, reserve_val))); - tcg_gen_brcond_i64(TCG_COND_NE, t0, t1, lab_fail); + tcg_gen_xor_tl(t1, t1, cpu_reserve_val2); + tcg_gen_xor_tl(t0, t0, cpu_reserve_val); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); - tcg_gen_addi_i64(t0, cpu_reserve, 8); - gen_qemu_ld64_i64(ctx, t0, t0); - tcg_gen_ld_i64(t1, cpu_env, (ctx->le_mode - ? offsetof(CPUPPCState, reserve_val) - : offsetof(CPUPPCState, reserve_val2))); - tcg_gen_brcond_i64(TCG_COND_NE, t0, t1, lab_fail); + tcg_gen_setcondi_tl(TCG_COND_EQ, t0, t0, 0); + tcg_gen_shli_tl(t0, t0, CRF_EQ_BIT); + tcg_gen_or_tl(t0, t0, cpu_so); + tcg_gen_trunc_tl_i32(cpu_crf[0], t0); + tcg_temp_free(t0); - /* Success */ - gen_qemu_st64_i64(ctx, ctx->le_mode ? lo : hi, cpu_reserve); - tcg_gen_addi_i64(t0, cpu_reserve, 8); - gen_qemu_st64_i64(ctx, ctx->le_mode ? hi : lo, t0); + tcg_gen_br(lab_over); + gen_set_label(lab_fail); - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); - tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); - tcg_gen_br(lab_over); + /* + * Address mismatch implies failure. But we still need to provide + * the memory barrier semantics of the instruction. + */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); - gen_set_label(lab_fail); - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); - - gen_set_label(lab_over); - tcg_gen_movi_tl(cpu_reserve, -1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - } + gen_set_label(lab_over); + tcg_gen_movi_tl(cpu_reserve, -1); } #endif /* defined(TARGET_PPC64) */ From 29b8de001f8ea2f36d4de5a250d1150492311529 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 1 Nov 2022 12:13:00 +0100 Subject: [PATCH 492/814] tests/tcg/s390x: Add div.c Add a basic test to prevent regressions. Signed-off-by: Ilya Leoshkevich Message-Id: <20221101111300.2539919-1-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- tests/tcg/s390x/Makefile.target | 1 + tests/tcg/s390x/div.c | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/tcg/s390x/div.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 07fcc6d0ce..ab7a3bcfb2 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -24,6 +24,7 @@ TESTS+=trap TESTS+=signals-s390x TESTS+=branch-relative-long TESTS+=noexec +TESTS+=div Z13_TESTS=vistr $(Z13_TESTS): CFLAGS+=-march=z13 -O2 diff --git a/tests/tcg/s390x/div.c b/tests/tcg/s390x/div.c new file mode 100644 index 0000000000..5807295614 --- /dev/null +++ b/tests/tcg/s390x/div.c @@ -0,0 +1,40 @@ +#include +#include + +static void test_dr(void) +{ + register int32_t r0 asm("r0") = -1; + register int32_t r1 asm("r1") = -4241; + int32_t b = 101, q, r; + + asm("dr %[r0],%[b]" + : [r0] "+r" (r0), [r1] "+r" (r1) + : [b] "r" (b) + : "cc"); + q = r1; + r = r0; + assert(q == -41); + assert(r == -100); +} + +static void test_dlr(void) +{ + register uint32_t r0 asm("r0") = 0; + register uint32_t r1 asm("r1") = 4243; + uint32_t b = 101, q, r; + + asm("dlr %[r0],%[b]" + : [r0] "+r" (r0), [r1] "+r" (r1) + : [b] "r" (b) + : "cc"); + q = r1; + r = r0; + assert(q == 42); + assert(r == 1); +} + +int main(void) +{ + test_dr(); + test_dlr(); +} From c432198ab09205d06ba9cf53cb4610d5fae22aa7 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 25 Oct 2022 23:30:08 +0200 Subject: [PATCH 493/814] tests/tcg/s390x: Add clst.c Add a basic test to prevent regressions. Signed-off-by: Ilya Leoshkevich Message-Id: <20221025213008.2209006-2-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- tests/tcg/s390x/Makefile.target | 1 + tests/tcg/s390x/clst.c | 82 +++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/tcg/s390x/clst.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index ab7a3bcfb2..79250f31dd 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -25,6 +25,7 @@ TESTS+=signals-s390x TESTS+=branch-relative-long TESTS+=noexec TESTS+=div +TESTS+=clst Z13_TESTS=vistr $(Z13_TESTS): CFLAGS+=-march=z13 -O2 diff --git a/tests/tcg/s390x/clst.c b/tests/tcg/s390x/clst.c new file mode 100644 index 0000000000..ed2fe7326c --- /dev/null +++ b/tests/tcg/s390x/clst.c @@ -0,0 +1,82 @@ +#define _GNU_SOURCE +#include +#include + +static int clst(char sep, const char **s1, const char **s2) +{ + const char *r1 = *s1; + const char *r2 = *s2; + int cc; + + do { + register int r0 asm("r0") = sep; + + asm("clst %[r1],%[r2]\n" + "ipm %[cc]\n" + "srl %[cc],28" + : [r1] "+r" (r1), [r2] "+r" (r2), "+r" (r0), [cc] "=r" (cc) + : + : "cc"); + *s1 = r1; + *s2 = r2; + } while (cc == 3); + + return cc; +} + +static const struct test { + const char *name; + char sep; + const char *s1; + const char *s2; + int exp_cc; + int exp_off; +} tests[] = { + { + .name = "cc0", + .sep = 0, + .s1 = "aa", + .s2 = "aa", + .exp_cc = 0, + .exp_off = 0, + }, + { + .name = "cc1", + .sep = 1, + .s1 = "a\x01", + .s2 = "aa\x01", + .exp_cc = 1, + .exp_off = 1, + }, + { + .name = "cc2", + .sep = 2, + .s1 = "abc\x02", + .s2 = "abb\x02", + .exp_cc = 2, + .exp_off = 2, + }, +}; + +int main(void) +{ + const struct test *t; + const char *s1, *s2; + size_t i; + int cc; + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + t = &tests[i]; + s1 = t->s1; + s2 = t->s2; + cc = clst(t->sep, &s1, &s2); + if (cc != t->exp_cc || + s1 != t->s1 + t->exp_off || + s2 != t->s2 + t->exp_off) { + fprintf(stderr, "%s\n", t->name); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} From 521d38ec9b4da82576dfcd3c5b6a2172cda25736 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 16:09:30 +1000 Subject: [PATCH 494/814] tests/tcg/s390x: Add long-double.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tests/tcg/s390x/Makefile.target | 1 + tests/tcg/s390x/long-double.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/tcg/s390x/long-double.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 79250f31dd..1d454270c0 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -26,6 +26,7 @@ TESTS+=branch-relative-long TESTS+=noexec TESTS+=div TESTS+=clst +TESTS+=long-double Z13_TESTS=vistr $(Z13_TESTS): CFLAGS+=-march=z13 -O2 diff --git a/tests/tcg/s390x/long-double.c b/tests/tcg/s390x/long-double.c new file mode 100644 index 0000000000..757a6262fd --- /dev/null +++ b/tests/tcg/s390x/long-double.c @@ -0,0 +1,24 @@ +/* + * Perform some basic arithmetic with long double, as a sanity check. + * With small integral numbers, we can cross-check with integers. + */ + +#include + +int main() +{ + int i, j; + + for (i = 1; i < 5; i++) { + for (j = 1; j < 5; j++) { + long double la = (long double)i + j; + long double lm = (long double)i * j; + long double ls = (long double)i - j; + + assert(la == i + j); + assert(lm == i * j); + assert(ls == i - j); + } + } + return 0; +} From 82f6584c9b1345489a6446b3bc4086e00e8d67d1 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Wed, 1 Feb 2023 14:32:57 +0100 Subject: [PATCH 495/814] tests/tcg/s390x: Add cdsg.c Add a simple test to prevent regressions. Signed-off-by: Ilya Leoshkevich Message-Id: <20230201133257.3223115-1-iii@linux.ibm.com> Signed-off-by: Richard Henderson --- tests/tcg/s390x/Makefile.target | 4 ++ tests/tcg/s390x/cdsg.c | 93 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 tests/tcg/s390x/cdsg.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 1d454270c0..72ad309b27 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -27,6 +27,10 @@ TESTS+=noexec TESTS+=div TESTS+=clst TESTS+=long-double +TESTS+=cdsg + +cdsg: CFLAGS+=-pthread +cdsg: LDFLAGS+=-pthread Z13_TESTS=vistr $(Z13_TESTS): CFLAGS+=-march=z13 -O2 diff --git a/tests/tcg/s390x/cdsg.c b/tests/tcg/s390x/cdsg.c new file mode 100644 index 0000000000..800618ff4b --- /dev/null +++ b/tests/tcg/s390x/cdsg.c @@ -0,0 +1,93 @@ +/* + * Test CDSG instruction. + * + * Increment the first half of aligned_quadword by 1, and the second half by 2 + * from 2 threads. Verify that the result is consistent. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include +#include +#include + +static volatile bool start; +typedef unsigned long aligned_quadword[2] __attribute__((__aligned__(16))); +static aligned_quadword val; +static const int n_iterations = 1000000; + +static inline int cdsg(unsigned long *orig0, unsigned long *orig1, + unsigned long new0, unsigned long new1, + aligned_quadword *mem) +{ + register unsigned long r0 asm("r0"); + register unsigned long r1 asm("r1"); + register unsigned long r2 asm("r2"); + register unsigned long r3 asm("r3"); + int cc; + + r0 = *orig0; + r1 = *orig1; + r2 = new0; + r3 = new1; + asm("cdsg %[r0],%[r2],%[db2]\n" + "ipm %[cc]" + : [r0] "+r" (r0) + , [r1] "+r" (r1) + , [db2] "+m" (*mem) + , [cc] "=r" (cc) + : [r2] "r" (r2) + , [r3] "r" (r3) + : "cc"); + *orig0 = r0; + *orig1 = r1; + + return (cc >> 28) & 3; +} + +void *cdsg_loop(void *arg) +{ + unsigned long orig0, orig1, new0, new1; + int cc; + int i; + + while (!start) { + } + + orig0 = val[0]; + orig1 = val[1]; + for (i = 0; i < n_iterations;) { + new0 = orig0 + 1; + new1 = orig1 + 2; + + cc = cdsg(&orig0, &orig1, new0, new1, &val); + + if (cc == 0) { + orig0 = new0; + orig1 = new1; + i++; + } else { + assert(cc == 1); + } + } + + return NULL; +} + +int main(void) +{ + pthread_t thread; + int ret; + + ret = pthread_create(&thread, NULL, cdsg_loop, NULL); + assert(ret == 0); + start = true; + cdsg_loop(NULL); + ret = pthread_join(thread, NULL); + assert(ret == 0); + + assert(val[0] == n_iterations * 2); + assert(val[1] == n_iterations * 4); + + return EXIT_SUCCESS; +} From 6d28ff406c71c2c6f8a79edb1ccfc17978aa95fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 08:18:59 +1000 Subject: [PATCH 496/814] target/s390x: Use a single return for helper_divs32/u32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pack the quotient and remainder into a single uint64_t. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- v2: Fix operand ordering; use tcg_extr32_i64. --- target/s390x/helper.h | 2 +- target/s390x/tcg/int_helper.c | 26 +++++++++++++------------- target/s390x/tcg/translate.c | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 93923ca153..bc828d976b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -10,7 +10,7 @@ DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_3(clcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) -DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, i64, env, s64, s64) DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index 954542388a..7260583cf2 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -34,45 +34,45 @@ #endif /* 64/32 -> 32 signed division */ -int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) +uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) { - int32_t ret, b = b64; - int64_t q; + int32_t b = b64; + int64_t q, r; if (b == 0) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } - ret = q = a / b; - env->retxl = a % b; + q = a / b; + r = a % b; /* Catch non-representable quotient. */ - if (ret != q) { + if (q != (int32_t)q) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } - return ret; + return deposit64(q, 32, 32, r); } /* 64/32 -> 32 unsigned division */ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) { - uint32_t ret, b = b64; - uint64_t q; + uint32_t b = b64; + uint64_t q, r; if (b == 0) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } - ret = q = a / b; - env->retxl = a % b; + q = a / b; + r = a % b; /* Catch non-representable quotient. */ - if (ret != q) { + if (q != (uint32_t)q) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } - return ret; + return deposit64(q, 32, 32, r); } /* 64/64 -> 64 signed division */ diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index a339b277e9..169f7ee1b2 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -2395,15 +2395,15 @@ static DisasJumpType op_diag(DisasContext *s, DisasOps *o) static DisasJumpType op_divs32(DisasContext *s, DisasOps *o) { - gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); - return_low128(o->out); + gen_helper_divs32(o->out, cpu_env, o->in1, o->in2); + tcg_gen_extr32_i64(o->out2, o->out, o->out); return DISAS_NEXT; } static DisasJumpType op_divu32(DisasContext *s, DisasOps *o) { - gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2); - return_low128(o->out); + gen_helper_divu32(o->out, cpu_env, o->in1, o->in2); + tcg_gen_extr32_i64(o->out2, o->out, o->out); return DISAS_NEXT; } From 4e5712f9037c34bbd9ffd78baa9d1ebea13a430d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 09:08:52 +1000 Subject: [PATCH 497/814] target/s390x: Use a single return for helper_divs64/u64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pack the quotient and remainder into a single Int128. Use the divu128 primitive to remove the cpu_abort on 32-bit hosts. Reviewed-by: Philippe Mathieu-Daudé Acked-by: Ilya Leoshkevich Signed-off-by: Richard Henderson --- v2: Extended div test case to cover these insns. --- target/s390x/helper.h | 4 ++-- target/s390x/tcg/int_helper.c | 38 +++++++++-------------------------- target/s390x/tcg/translate.c | 14 +++++++++---- tests/tcg/s390x/div.c | 35 ++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index bc828d976b..593f3c8bee 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -12,8 +12,8 @@ DEF_HELPER_3(clcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, i64, env, s64, s64) DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) -DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, i128, env, s64, s64) +DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i128, env, i64, i64, i64) DEF_HELPER_3(srst, void, env, i32, i32) DEF_HELPER_3(srstu, void, env, i32, i32) DEF_HELPER_4(clst, i64, env, i64, i64, i64) diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index 7260583cf2..eb8e6dd1b5 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -76,46 +76,26 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) } /* 64/64 -> 64 signed division */ -int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) +Int128 HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) { /* Catch divide by zero, and non-representable quotient (MIN / -1). */ if (b == 0 || (b == -1 && a == (1ll << 63))) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } - env->retxl = a % b; - return a / b; + return int128_make128(a / b, a % b); } /* 128 -> 64/64 unsigned division */ -uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t b) +Int128 HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b) { - uint64_t ret; - /* Signal divide by zero. */ - if (b == 0) { - tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); - } - if (ah == 0) { - /* 64 -> 64/64 case */ - env->retxl = al % b; - ret = al / b; - } else { - /* ??? Move i386 idivq helper to host-utils. */ -#ifdef CONFIG_INT128 - __uint128_t a = ((__uint128_t)ah << 64) | al; - __uint128_t q = a / b; - env->retxl = a % b; - ret = q; - if (ret != q) { - tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); + if (b != 0) { + uint64_t r = divu128(&al, &ah, b); + if (ah == 0) { + return int128_make128(al, r); } -#else - /* 32-bit hosts would need special wrapper functionality - just abort if - we encounter such a case; it's very unlikely anyways. */ - cpu_abort(env_cpu(env), "128 -> 64/64 division not implemented\n"); -#endif } - return ret; + /* divide by zero or overflow */ + tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } uint64_t HELPER(cvd)(int32_t reg) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 169f7ee1b2..6953b81de7 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -2409,15 +2409,21 @@ static DisasJumpType op_divu32(DisasContext *s, DisasOps *o) static DisasJumpType op_divs64(DisasContext *s, DisasOps *o) { - gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2); - return_low128(o->out); + TCGv_i128 t = tcg_temp_new_i128(); + + gen_helper_divs64(t, cpu_env, o->in1, o->in2); + tcg_gen_extr_i128_i64(o->out2, o->out, t); + tcg_temp_free_i128(t); return DISAS_NEXT; } static DisasJumpType op_divu64(DisasContext *s, DisasOps *o) { - gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2); - return_low128(o->out); + TCGv_i128 t = tcg_temp_new_i128(); + + gen_helper_divu64(t, cpu_env, o->out, o->out2, o->in2); + tcg_gen_extr_i128_i64(o->out2, o->out, t); + tcg_temp_free_i128(t); return DISAS_NEXT; } diff --git a/tests/tcg/s390x/div.c b/tests/tcg/s390x/div.c index 5807295614..6ad9900e08 100644 --- a/tests/tcg/s390x/div.c +++ b/tests/tcg/s390x/div.c @@ -33,8 +33,43 @@ static void test_dlr(void) assert(r == 1); } +static void test_dsgr(void) +{ + register int64_t r0 asm("r0") = -1; + register int64_t r1 asm("r1") = -4241; + int64_t b = 101, q, r; + + asm("dsgr %[r0],%[b]" + : [r0] "+r" (r0), [r1] "+r" (r1) + : [b] "r" (b) + : "cc"); + q = r1; + r = r0; + assert(q == -41); + assert(r == -100); +} + +static void test_dlgr(void) +{ + register uint64_t r0 asm("r0") = 0; + register uint64_t r1 asm("r1") = 4243; + uint64_t b = 101, q, r; + + asm("dlgr %[r0],%[b]" + : [r0] "+r" (r0), [r1] "+r" (r1) + : [b] "r" (b) + : "cc"); + q = r1; + r = r0; + assert(q == 42); + assert(r == 1); +} + int main(void) { test_dr(); test_dlr(); + test_dsgr(); + test_dlgr(); + return 0; } From b71dd2a51e898ee91bee3e23708e8d4d14ac6812 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 11:46:06 +1000 Subject: [PATCH 498/814] target/s390x: Use Int128 for return from CLST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Acked-by: Ilya Leoshkevich Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/tcg/mem_helper.c | 11 ++++------- target/s390x/tcg/translate.c | 8 ++++++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 593f3c8bee..25c2dd0b3c 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -16,7 +16,7 @@ DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, i128, env, s64, s64) DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i128, env, i64, i64, i64) DEF_HELPER_3(srst, void, env, i32, i32) DEF_HELPER_3(srstu, void, env, i32, i32) -DEF_HELPER_4(clst, i64, env, i64, i64, i64) +DEF_HELPER_4(clst, i128, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mvn, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvo, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, env, i64, i32, i32) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index cb82cd1c1d..9be42851d8 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -886,7 +886,7 @@ void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2) } /* unsigned string compare (c is string terminator) */ -uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) +Int128 HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) { uintptr_t ra = GETPC(); uint32_t len; @@ -904,23 +904,20 @@ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) if (v1 == c) { /* Equal. CC=0, and don't advance the registers. */ env->cc_op = 0; - env->retxl = s2; - return s1; + return int128_make128(s2, s1); } } else { /* Unequal. CC={1,2}, and advance the registers. Note that the terminator need not be zero, but the string that contains the terminator is by definition "low". */ env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2); - env->retxl = s2 + len; - return s1 + len; + return int128_make128(s2 + len, s1 + len); } } /* CPU-determined bytes equal; advance the registers. */ env->cc_op = 3; - env->retxl = s2 + len; - return s1 + len; + return int128_make128(s2 + len, s1 + len); } /* move page */ diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 6953b81de7..8397fe2bd8 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -2164,9 +2164,13 @@ static DisasJumpType op_clm(DisasContext *s, DisasOps *o) static DisasJumpType op_clst(DisasContext *s, DisasOps *o) { - gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); + TCGv_i128 pair = tcg_temp_new_i128(); + + gen_helper_clst(pair, cpu_env, regs[0], o->in1, o->in2); + tcg_gen_extr_i128_i64(o->in2, o->in1, pair); + tcg_temp_free_i128(pair); + set_cc_static(s); - return_low128(o->in2); return DISAS_NEXT; } From c91192245ac32c219ba698e3ca5e976cbed3359b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 11:51:10 +1000 Subject: [PATCH 499/814] target/s390x: Use Int128 for return from CKSM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/tcg/mem_helper.c | 7 +++---- target/s390x/tcg/translate.c | 6 ++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 25c2dd0b3c..03b29efa3e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -103,7 +103,7 @@ DEF_HELPER_4(tre, i64, env, i64, i64, i64) DEF_HELPER_4(trt, i32, env, i32, i64, i64) DEF_HELPER_4(trtr, i32, env, i32, i64, i64) DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32) -DEF_HELPER_4(cksm, i64, env, i64, i64, i64) +DEF_HELPER_4(cksm, i128, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 9be42851d8..b0b403e23a 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -1350,8 +1350,8 @@ uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* checksum */ -uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, - uint64_t src, uint64_t src_len) +Int128 HELPER(cksm)(CPUS390XState *env, uint64_t r1, + uint64_t src, uint64_t src_len) { uintptr_t ra = GETPC(); uint64_t max_len, len; @@ -1392,8 +1392,7 @@ uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, env->cc_op = (len == src_len ? 0 : 3); /* Return both cksm and processed length. */ - env->retxl = cksm; - return len; + return int128_make128(cksm, len); } void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 8397fe2bd8..1a7aa9e4ae 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -2041,11 +2041,13 @@ static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o) static DisasJumpType op_cksm(DisasContext *s, DisasOps *o) { int r2 = get_field(s, r2); + TCGv_i128 pair = tcg_temp_new_i128(); TCGv_i64 len = tcg_temp_new_i64(); - gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); + gen_helper_cksm(pair, cpu_env, o->in1, o->in2, regs[r2 + 1]); set_cc_static(s); - return_low128(o->out); + tcg_gen_extr_i128_i64(o->out, len, pair); + tcg_temp_free_i128(pair); tcg_gen_add_i64(regs[r2], regs[r2], len); tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len); From ef45f5b998126205e0362c7af4c5d6ee65801450 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 12:00:07 +1000 Subject: [PATCH 500/814] target/s390x: Use Int128 for return from TRE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/tcg/mem_helper.c | 7 +++---- target/s390x/tcg/translate.c | 7 +++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 03b29efa3e..b4170a4256 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -99,7 +99,7 @@ DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, i64) DEF_HELPER_FLAGS_4(unpku, TCG_CALL_NO_WG, i32, env, i64, i32, i64) DEF_HELPER_FLAGS_3(tp, TCG_CALL_NO_WG, i32, env, i64, i32) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) -DEF_HELPER_4(tre, i64, env, i64, i64, i64) +DEF_HELPER_4(tre, i128, env, i64, i64, i64) DEF_HELPER_4(trt, i32, env, i32, i64, i64) DEF_HELPER_4(trtr, i32, env, i32, i64, i64) DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index b0b403e23a..49969abda7 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -1632,8 +1632,8 @@ void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, do_helper_tr(env, len, array, trans, GETPC()); } -uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, - uint64_t len, uint64_t trans) +Int128 HELPER(tre)(CPUS390XState *env, uint64_t array, + uint64_t len, uint64_t trans) { uintptr_t ra = GETPC(); uint8_t end = env->regs[0] & 0xff; @@ -1668,8 +1668,7 @@ uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, } env->cc_op = cc; - env->retxl = len - i; - return array + i; + return int128_make128(len - i, array + i); } static inline uint32_t do_helper_trt(CPUS390XState *env, int len, diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 1a7aa9e4ae..f3e4b70ed9 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -4905,8 +4905,11 @@ static DisasJumpType op_tr(DisasContext *s, DisasOps *o) static DisasJumpType op_tre(DisasContext *s, DisasOps *o) { - gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2); - return_low128(o->out2); + TCGv_i128 pair = tcg_temp_new_i128(); + + gen_helper_tre(pair, cpu_env, o->out, o->out2, o->in2); + tcg_gen_extr_i128_i64(o->out2, o->out, pair); + tcg_temp_free_i128(pair); set_cc_static(s); return DISAS_NEXT; } From f4031d9664d6db63dc384e1bca38739b2cb50acd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 15:18:56 +1000 Subject: [PATCH 501/814] target/s390x: Copy wout_x1 to wout_x1_P MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make a copy of wout_x1 before modifying it, as wout_x1_P emphasizing that it operates on the out/out2 pair. The insns that use x1_P are data movement that will not change to Int128. Acked-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/s390x/tcg/insn-data.h.inc | 12 ++++++------ target/s390x/tcg/translate.c | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc index 79c6ab509a..d0814cb218 100644 --- a/target/s390x/tcg/insn-data.h.inc +++ b/target/s390x/tcg/insn-data.h.inc @@ -422,7 +422,7 @@ F(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0, IF_AFP1 | IF_AFP2) F(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) F(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0, IF_AFP1) - F(0xb365, LXR, RRE, Z, x2h, x2l, 0, x1, movx, 0, IF_AFP1) + F(0xb365, LXR, RRE, Z, x2h, x2l, 0, x1_P, movx, 0, IF_AFP1) /* LOAD IMMEDIATE */ C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) /* LOAD RELATIVE LONG */ @@ -461,7 +461,7 @@ C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) F(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32, IF_BFP) F(0xb312, LTDBR, RRE, Z, 0, f2, 0, f1, mov2, f64, IF_BFP) - F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1, movx, f128, IF_BFP) + F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1_P, movx, f128, IF_BFP) /* LOAD AND TRAP */ C(0xe39f, LAT, RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0) C(0xe385, LGAT, RXY_a, LAT, 0, a2, r1, 0, lgat, 0) @@ -483,7 +483,7 @@ C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) F(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32, IF_BFP) F(0xb313, LCDBR, RRE, Z, 0, f2, new, f1, negf64, f64, IF_BFP) - F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1, negf128, f128, IF_BFP) + F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1_P, negf128, f128, IF_BFP) F(0xb373, LCDFR, RRE, FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2) /* LOAD COUNT TO BLOCK BOUNDARY */ C(0xe727, LCBB, RXE, V, la2, 0, r1, 0, lcbb, 0) @@ -552,7 +552,7 @@ C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) F(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32, IF_BFP) F(0xb311, LNDBR, RRE, Z, 0, f2, new, f1, nabsf64, f64, IF_BFP) - F(0xb341, LNXBR, RRE, Z, x2h, x2l, new_P, x1, nabsf128, f128, IF_BFP) + F(0xb341, LNXBR, RRE, Z, x2h, x2l, new_P, x1_P, nabsf128, f128, IF_BFP) F(0xb371, LNDFR, RRE, FPSSH, 0, f2, new, f1, nabsf64, 0, IF_AFP1 | IF_AFP2) /* LOAD ON CONDITION */ C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) @@ -577,7 +577,7 @@ C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) F(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32, IF_BFP) F(0xb310, LPDBR, RRE, Z, 0, f2, new, f1, absf64, f64, IF_BFP) - F(0xb340, LPXBR, RRE, Z, x2h, x2l, new_P, x1, absf128, f128, IF_BFP) + F(0xb340, LPXBR, RRE, Z, x2h, x2l, new_P, x1_P, absf128, f128, IF_BFP) F(0xb370, LPDFR, RRE, FPSSH, 0, f2, new, f1, absf64, 0, IF_AFP1 | IF_AFP2) /* LOAD REVERSED */ C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) @@ -588,7 +588,7 @@ /* LOAD ZERO */ F(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0, IF_AFP1) F(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0, IF_AFP1) - F(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0, IF_AFP1) + F(0xb376, LZXR, RRE, Z, 0, 0, 0, x1_P, zero2, 0, IF_AFP1) /* LOAD FPC */ F(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0, IF_BFP) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index f3e4b70ed9..d25b6f3c03 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -5518,6 +5518,14 @@ static void wout_x1(DisasContext *s, DisasOps *o) } #define SPEC_wout_x1 SPEC_r1_f128 +static void wout_x1_P(DisasContext *s, DisasOps *o) +{ + int f1 = get_field(s, r1); + store_freg(f1, o->out); + store_freg(f1 + 2, o->out2); +} +#define SPEC_wout_x1_P SPEC_r1_f128 + static void wout_cond_r1r2_32(DisasContext *s, DisasOps *o) { if (get_field(s, r1) != get_field(s, r2)) { From ee5e866fd2304a08172c3674dd7c7e7a97b046ed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Oct 2022 10:15:49 +1000 Subject: [PATCH 502/814] target/s390x: Use Int128 for returning float128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- v2: Remove extraneous return_low128. --- target/s390x/helper.h | 22 +++++++------- target/s390x/tcg/fpu_helper.c | 29 +++++++++--------- target/s390x/tcg/insn-data.h.inc | 20 ++++++------- target/s390x/tcg/translate.c | 51 +++++++++++++++++--------------- 4 files changed, 63 insertions(+), 59 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index b4170a4256..d40aeb471f 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -31,32 +31,32 @@ DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_4(clclu, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) DEF_HELPER_3(cdgb, i64, env, s64, i32) -DEF_HELPER_3(cxgb, i64, env, s64, i32) +DEF_HELPER_3(cxgb, i128, env, s64, i32) DEF_HELPER_3(celgb, i64, env, i64, i32) DEF_HELPER_3(cdlgb, i64, env, i64, i32) -DEF_HELPER_3(cxlgb, i64, env, i64, i32) +DEF_HELPER_3(cxlgb, i128, env, i64, i32) DEF_HELPER_4(cdsg, void, env, i64, i32, i32) DEF_HELPER_4(cdsg_parallel, void, env, i64, i32, i32) DEF_HELPER_4(csst, i32, env, i32, i64, i64) DEF_HELPER_4(csst_parallel, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) -DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i128, env, i64, i64, i64) DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_4(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) -DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i128, env, i64) +DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i128, env, i64) DEF_HELPER_FLAGS_3(ledb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_4(lexb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) @@ -79,7 +79,7 @@ DEF_HELPER_3(clfdb, i64, env, i64, i32) DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32) -DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i128, env, i64, i64, i32) DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) @@ -89,7 +89,7 @@ DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_4(tcxb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64, i64) DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i128, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index be80b2373c..13be44499b 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -34,7 +34,10 @@ #define HELPER_LOG(x...) #endif -#define RET128(F) (env->retxl = F.low, F.high) +static inline Int128 RET128(float128 f) +{ + return int128_make128(f.low, f.high); +} uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) { @@ -224,7 +227,7 @@ uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP addition */ -uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, +Int128 HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { float128 ret = float128_add(make_float128(ah, al), @@ -251,7 +254,7 @@ uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP subtraction */ -uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, +Int128 HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { float128 ret = float128_sub(make_float128(ah, al), @@ -278,7 +281,7 @@ uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP division */ -uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, +Int128 HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { float128 ret = float128_div(make_float128(ah, al), @@ -314,7 +317,7 @@ uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP multiplication */ -uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, +Int128 HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t bh, uint64_t bl) { float128 ret = float128_mul(make_float128(ah, al), @@ -325,8 +328,7 @@ uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, } /* 128/64-bit FP multiplication */ -uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t f2) +Int128 HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t f2) { float128 ret = float64_to_float128(f2, &env->fpu_status); ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); @@ -355,7 +357,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al, } /* convert 64-bit float to 128-bit float */ -uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) +Int128 HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { float128 ret = float64_to_float128(f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); @@ -363,7 +365,7 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) } /* convert 32-bit float to 128-bit float */ -uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) +Int128 HELPER(lxeb)(CPUS390XState *env, uint64_t f2) { float128 ret = float32_to_float128(f2, &env->fpu_status); handle_exceptions(env, false, GETPC()); @@ -486,7 +488,7 @@ uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) } /* convert 64-bit int to 128-bit float */ -uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) +Int128 HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = int64_to_float128(v2, &env->fpu_status); @@ -519,7 +521,7 @@ uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) } /* convert 64-bit uint to 128-bit float */ -uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) +Int128 HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = uint64_to_float128(v2, &env->fpu_status); @@ -748,8 +750,7 @@ uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) } /* round to integer 128-bit */ -uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint32_t m34) +Int128 HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); float128 ret = float128_round_to_int(make_float128(ah, al), @@ -890,7 +891,7 @@ uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) } /* square root 128-bit */ -uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +Int128 HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); handle_exceptions(env, false, GETPC()); diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc index d0814cb218..517a4500ae 100644 --- a/target/s390x/tcg/insn-data.h.inc +++ b/target/s390x/tcg/insn-data.h.inc @@ -306,10 +306,10 @@ /* CONVERT FROM FIXED */ F(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0, IF_BFP) F(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, new, f1, cdgb, 0, IF_BFP) - F(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, new_P, x1, cxgb, 0, IF_BFP) + F(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, new_x, x1, cxgb, 0, IF_BFP) F(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0, IF_BFP) F(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, new, f1, cdgb, 0, IF_BFP) - F(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, new_P, x1, cxgb, 0, IF_BFP) + F(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, new_x, x1, cxgb, 0, IF_BFP) /* CONVERT TO LOGICAL */ F(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP) F(0xb39d, CLFDBR, RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP) @@ -320,10 +320,10 @@ /* CONVERT FROM LOGICAL */ F(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP) F(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP) - F(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, new_P, x1, cxlgb, 0, IF_BFP) + F(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, new_x, x1, cxlgb, 0, IF_BFP) F(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0, IF_BFP) F(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, new, f1, cdlgb, 0, IF_BFP) - F(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, new_P, x1, cxlgb, 0, IF_BFP) + F(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, new_x, x1, cxlgb, 0, IF_BFP) /* CONVERT UTF-8 TO UTF-16 */ D(0xb2a7, CU12, RRF_c, Z, 0, 0, 0, 0, cuXX, 0, 12) @@ -597,15 +597,15 @@ /* LOAD FP INTEGER */ F(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0, IF_BFP) F(0xb35f, FIDBR, RRF_e, Z, 0, f2, new, f1, fidb, 0, IF_BFP) - F(0xb347, FIXBR, RRF_e, Z, x2h, x2l, new_P, x1, fixb, 0, IF_BFP) + F(0xb347, FIXBR, RRF_e, Z, x2h, x2l, new_x, x1, fixb, 0, IF_BFP) /* LOAD LENGTHENED */ F(0xb304, LDEBR, RRE, Z, 0, e2, new, f1, ldeb, 0, IF_BFP) - F(0xb305, LXDBR, RRE, Z, 0, f2, new_P, x1, lxdb, 0, IF_BFP) - F(0xb306, LXEBR, RRE, Z, 0, e2, new_P, x1, lxeb, 0, IF_BFP) + F(0xb305, LXDBR, RRE, Z, 0, f2, new_x, x1, lxdb, 0, IF_BFP) + F(0xb306, LXEBR, RRE, Z, 0, e2, new_x, x1, lxeb, 0, IF_BFP) F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP) - F(0xed05, LXDB, RXE, Z, 0, m2_64, new_P, x1, lxdb, 0, IF_BFP) - F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_P, x1, lxeb, 0, IF_BFP) + F(0xed05, LXDB, RXE, Z, 0, m2_64, new_x, x1, lxdb, 0, IF_BFP) + F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_x, x1, lxeb, 0, IF_BFP) F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1) F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1) /* LOAD ROUNDED */ @@ -835,7 +835,7 @@ /* SQUARE ROOT */ F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP) - F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_P, x1, sqxb, 0, IF_BFP) + F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_x, x1, sqxb, 0, IF_BFP) F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP) F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index d25b6f3c03..0a750a5467 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -1103,6 +1103,7 @@ typedef struct { bool g_out, g_out2, g_in1, g_in2; TCGv_i64 out, out2, in1, in2; TCGv_i64 addr1; + TCGv_i128 out_128; } DisasOps; /* Instructions can place constraints on their operands, raising specification @@ -1461,8 +1462,7 @@ static DisasJumpType op_adb(DisasContext *s, DisasOps *o) static DisasJumpType op_axb(DisasContext *s, DisasOps *o) { - gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); - return_low128(o->out2); + gen_helper_axb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); return DISAS_NEXT; } @@ -1995,9 +1995,8 @@ static DisasJumpType op_cxgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cxgb(o->out, cpu_env, o->in2, m34); + gen_helper_cxgb(o->out_128, cpu_env, o->in2, m34); tcg_temp_free_i32(m34); - return_low128(o->out2); return DISAS_NEXT; } @@ -2032,9 +2031,8 @@ static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cxlgb(o->out, cpu_env, o->in2, m34); + gen_helper_cxlgb(o->out_128, cpu_env, o->in2, m34); tcg_temp_free_i32(m34); - return_low128(o->out2); return DISAS_NEXT; } @@ -2447,8 +2445,7 @@ static DisasJumpType op_ddb(DisasContext *s, DisasOps *o) static DisasJumpType op_dxb(DisasContext *s, DisasOps *o) { - gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); - return_low128(o->out2); + gen_helper_dxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); return DISAS_NEXT; } @@ -2553,8 +2550,7 @@ static DisasJumpType op_fixb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m34); - return_low128(o->out2); + gen_helper_fixb(o->out_128, cpu_env, o->in1, o->in2, m34); tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -2866,15 +2862,13 @@ static DisasJumpType op_lexb(DisasContext *s, DisasOps *o) static DisasJumpType op_lxdb(DisasContext *s, DisasOps *o) { - gen_helper_lxdb(o->out, cpu_env, o->in2); - return_low128(o->out2); + gen_helper_lxdb(o->out_128, cpu_env, o->in2); return DISAS_NEXT; } static DisasJumpType op_lxeb(DisasContext *s, DisasOps *o) { - gen_helper_lxeb(o->out, cpu_env, o->in2); - return_low128(o->out2); + gen_helper_lxeb(o->out_128, cpu_env, o->in2); return DISAS_NEXT; } @@ -3590,15 +3584,13 @@ static DisasJumpType op_mdb(DisasContext *s, DisasOps *o) static DisasJumpType op_mxb(DisasContext *s, DisasOps *o) { - gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); - return_low128(o->out2); + gen_helper_mxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); return DISAS_NEXT; } static DisasJumpType op_mxdb(DisasContext *s, DisasOps *o) { - gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2); - return_low128(o->out2); + gen_helper_mxdb(o->out_128, cpu_env, o->out, o->out2, o->in2); return DISAS_NEXT; } @@ -4063,8 +4055,7 @@ static DisasJumpType op_sdb(DisasContext *s, DisasOps *o) static DisasJumpType op_sxb(DisasContext *s, DisasOps *o) { - gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); - return_low128(o->out2); + gen_helper_sxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); return DISAS_NEXT; } @@ -4082,8 +4073,7 @@ static DisasJumpType op_sqdb(DisasContext *s, DisasOps *o) static DisasJumpType op_sqxb(DisasContext *s, DisasOps *o) { - gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2); - return_low128(o->out2); + gen_helper_sqxb(o->out_128, cpu_env, o->in1, o->in2); return DISAS_NEXT; } @@ -5395,6 +5385,14 @@ static void prep_new_P(DisasContext *s, DisasOps *o) } #define SPEC_prep_new_P 0 +static void prep_new_x(DisasContext *s, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); + o->out2 = tcg_temp_new_i64(); + o->out_128 = tcg_temp_new_i128(); +} +#define SPEC_prep_new_x 0 + static void prep_r1(DisasContext *s, DisasOps *o) { o->out = regs[get_field(s, r1)]; @@ -5411,11 +5409,12 @@ static void prep_r1_P(DisasContext *s, DisasOps *o) } #define SPEC_prep_r1_P SPEC_r1_even -/* Whenever we need x1 in addition to other inputs, we'll load it to out/out2 */ static void prep_x1(DisasContext *s, DisasOps *o) { o->out = load_freg(get_field(s, r1)); o->out2 = load_freg(get_field(s, r1) + 2); + o->out_128 = tcg_temp_new_i128(); + tcg_gen_concat_i64_i128(o->out_128, o->out2, o->out); } #define SPEC_prep_x1 SPEC_r1_f128 @@ -5513,6 +5512,8 @@ static void wout_f1(DisasContext *s, DisasOps *o) static void wout_x1(DisasContext *s, DisasOps *o) { int f1 = get_field(s, r1); + + tcg_gen_extr_i128_i64(o->out2, o->out, o->out_128); store_freg(f1, o->out); store_freg(f1 + 2, o->out2); } @@ -6588,7 +6589,9 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) if (o.addr1) { tcg_temp_free_i64(o.addr1); } - + if (o.out_128) { + tcg_temp_free_i128(o.out_128); + } /* io should be the last instruction in tb when icount is enabled */ if (unlikely(icount && ret == DISAS_NEXT)) { ret = DISAS_TOO_MANY; From 2b91240f95fdb9acfa35ccac6cda2a42a16ac7f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Oct 2022 13:05:45 +1000 Subject: [PATCH 503/814] target/s390x: Use Int128 for passing float128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: David Hildenbrand Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- v2: Fix SPEC_in1_x1. --- target/s390x/helper.h | 32 ++++++------ target/s390x/tcg/fpu_helper.c | 88 ++++++++++++++------------------ target/s390x/tcg/insn-data.h.inc | 30 +++++------ target/s390x/tcg/translate.c | 76 ++++++++++++++++++--------- 4 files changed, 121 insertions(+), 105 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index d40aeb471f..bccd3bfca6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -41,55 +41,55 @@ DEF_HELPER_4(csst, i32, env, i32, i64, i64) DEF_HELPER_4(csst_parallel, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(axb, TCG_CALL_NO_WG, i128, env, i128, i128) DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(sxb, TCG_CALL_NO_WG, i128, env, i128, i128) DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(dxb, TCG_CALL_NO_WG, i128, env, i128, i128) DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i128, env, i64, i64, i64, i64) -DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i128, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(mxb, TCG_CALL_NO_WG, i128, env, i128, i128) +DEF_HELPER_FLAGS_3(mxdb, TCG_CALL_NO_WG, i128, env, i128, i64) DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_4(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(ldxb, TCG_CALL_NO_WG, i64, env, i128, i32) DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i128, env, i64) DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i128, env, i64) DEF_HELPER_FLAGS_3(ledb, TCG_CALL_NO_WG, i64, env, i64, i32) -DEF_HELPER_FLAGS_4(lexb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i128, i32) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) -DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(cxb, TCG_CALL_NO_WG_SE, i32, env, i128, i128) DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64) DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64) -DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(kxb, TCG_CALL_NO_WG, i32, env, i128, i128) DEF_HELPER_3(cgeb, i64, env, i64, i32) DEF_HELPER_3(cgdb, i64, env, i64, i32) -DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(cgxb, i64, env, i128, i32) DEF_HELPER_3(cfeb, i64, env, i64, i32) DEF_HELPER_3(cfdb, i64, env, i64, i32) -DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) +DEF_HELPER_3(cfxb, i64, env, i128, i32) DEF_HELPER_3(clgeb, i64, env, i64, i32) DEF_HELPER_3(clgdb, i64, env, i64, i32) -DEF_HELPER_4(clgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clgxb, i64, env, i128, i32) DEF_HELPER_3(clfeb, i64, env, i64, i32) DEF_HELPER_3(clfdb, i64, env, i64, i32) -DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clfxb, i64, env, i128, i32) DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32) -DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i128, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(fixb, TCG_CALL_NO_WG, i128, env, i128, i32) DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64) -DEF_HELPER_FLAGS_4(tcxb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, env, i128, i64) DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i128, env, i64, i64) +DEF_HELPER_FLAGS_2(sqxb, TCG_CALL_NO_WG, i128, env, i128) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index 13be44499b..0bdab5bcf7 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -39,6 +39,11 @@ static inline Int128 RET128(float128 f) return int128_make128(f.low, f.high); } +static inline float128 ARG128(Int128 i) +{ + return make_float128(int128_gethi(i), int128_getlo(i)); +} + uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) { uint8_t s390_exc = 0; @@ -227,12 +232,9 @@ uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP addition */ -Int128 HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +Int128 HELPER(axb)(CPUS390XState *env, Int128 a, Int128 b) { - float128 ret = float128_add(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + float128 ret = float128_add(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -254,12 +256,9 @@ uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP subtraction */ -Int128 HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +Int128 HELPER(sxb)(CPUS390XState *env, Int128 a, Int128 b) { - float128 ret = float128_sub(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + float128 ret = float128_sub(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -281,12 +280,9 @@ uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP division */ -Int128 HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b) { - float128 ret = float128_div(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + float128 ret = float128_div(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -317,21 +313,18 @@ uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP multiplication */ -Int128 HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +Int128 HELPER(mxb)(CPUS390XState *env, Int128 a, Int128 b) { - float128 ret = float128_mul(make_float128(ah, al), - make_float128(bh, bl), - &env->fpu_status); + float128 ret = float128_mul(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } /* 128/64-bit FP multiplication */ -Int128 HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t f2) +Int128 HELPER(mxdb)(CPUS390XState *env, Int128 a, uint64_t f2) { float128 ret = float64_to_float128(f2, &env->fpu_status); - ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); + ret = float128_mul(ARG128(a), ret, &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } @@ -345,11 +338,10 @@ uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) } /* convert 128-bit float to 64-bit float */ -uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint32_t m34) +uint64_t HELPER(ldxb)(CPUS390XState *env, Int128 a, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); + float64 ret = float128_to_float64(ARG128(a), &env->fpu_status); s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); @@ -384,11 +376,10 @@ uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) } /* convert 128-bit float to 32-bit float */ -uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint32_t m34) +uint64_t HELPER(lexb)(CPUS390XState *env, Int128 a, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); + float32 ret = float128_to_float32(ARG128(a), &env->fpu_status); s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); @@ -412,11 +403,9 @@ uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP compare */ -uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +uint32_t HELPER(cxb)(CPUS390XState *env, Int128 a, Int128 b) { - FloatRelation cmp = float128_compare_quiet(make_float128(ah, al), - make_float128(bh, bl), + FloatRelation cmp = float128_compare_quiet(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); @@ -564,10 +553,10 @@ uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) } /* convert 128-bit float to 64-bit int */ -uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) +uint64_t HELPER(cgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float128 v2 = make_float128(h, l); + float128 v2 = ARG128(i2); int64_t ret = float128_to_int64(v2, &env->fpu_status); uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); @@ -613,10 +602,10 @@ uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) } /* convert 128-bit float to 32-bit int */ -uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) +uint64_t HELPER(cfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float128 v2 = make_float128(h, l); + float128 v2 = ARG128(i2); int32_t ret = float128_to_int32(v2, &env->fpu_status); uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); @@ -662,10 +651,10 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) } /* convert 128-bit float to 64-bit uint */ -uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) +uint64_t HELPER(clgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float128 v2 = make_float128(h, l); + float128 v2 = ARG128(i2); uint64_t ret = float128_to_uint64(v2, &env->fpu_status); uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); @@ -711,10 +700,10 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) } /* convert 128-bit float to 32-bit uint */ -uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) +uint64_t HELPER(clfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float128 v2 = make_float128(h, l); + float128 v2 = ARG128(i2); uint32_t ret = float128_to_uint32(v2, &env->fpu_status); uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); @@ -750,11 +739,10 @@ uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) } /* round to integer 128-bit */ -Int128 HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m34) +Int128 HELPER(fixb)(CPUS390XState *env, Int128 a, uint32_t m34) { int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); - float128 ret = float128_round_to_int(make_float128(ah, al), - &env->fpu_status); + float128 ret = float128_round_to_int(ARG128(a), &env->fpu_status); s390_restore_bfp_rounding_mode(env, old_mode); handle_exceptions(env, xxc_from_m34(m34), GETPC()); @@ -778,11 +766,9 @@ uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) } /* 128-bit FP compare and signal */ -uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, - uint64_t bh, uint64_t bl) +uint32_t HELPER(kxb)(CPUS390XState *env, Int128 a, Int128 b) { - FloatRelation cmp = float128_compare(make_float128(ah, al), - make_float128(bh, bl), + FloatRelation cmp = float128_compare(ARG128(a), ARG128(b), &env->fpu_status); handle_exceptions(env, false, GETPC()); return float_comp_to_cc(env, cmp); @@ -869,9 +855,9 @@ uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2) +uint32_t HELPER(tcxb)(CPUS390XState *env, Int128 a, uint64_t m2) { - return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0; + return (m2 & float128_dcmask(env, ARG128(a))) != 0; } /* square root 32-bit */ @@ -891,9 +877,9 @@ uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) } /* square root 128-bit */ -Int128 HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +Int128 HELPER(sqxb)(CPUS390XState *env, Int128 a) { - float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); + float128 ret = float128_sqrt(ARG128(a), &env->fpu_status); handle_exceptions(env, false, GETPC()); return RET128(ret); } diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc index 517a4500ae..893f4b48db 100644 --- a/target/s390x/tcg/insn-data.h.inc +++ b/target/s390x/tcg/insn-data.h.inc @@ -34,7 +34,7 @@ C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) F(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32, IF_BFP) F(0xb31a, ADBR, RRE, Z, f1, f2, new, f1, adb, f64, IF_BFP) - F(0xb34a, AXBR, RRE, Z, x2h, x2l, x1, x1, axb, f128, IF_BFP) + F(0xb34a, AXBR, RRE, Z, x1, x2, new_x, x1, axb, f128, IF_BFP) F(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32, IF_BFP) F(0xed1a, ADB, RXE, Z, f1, m2_64, new, f1, adb, f64, IF_BFP) /* ADD HIGH */ @@ -172,13 +172,13 @@ C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) F(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0, IF_BFP) F(0xb319, CDBR, RRE, Z, f1, f2, 0, 0, cdb, 0, IF_BFP) - F(0xb349, CXBR, RRE, Z, x2h, x2l, x1, 0, cxb, 0, IF_BFP) + F(0xb349, CXBR, RRE, Z, x1, x2, 0, 0, cxb, 0, IF_BFP) F(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0, IF_BFP) F(0xed19, CDB, RXE, Z, f1, m2_64, 0, 0, cdb, 0, IF_BFP) /* COMPARE AND SIGNAL */ F(0xb308, KEBR, RRE, Z, e1, e2, 0, 0, keb, 0, IF_BFP) F(0xb318, KDBR, RRE, Z, f1, f2, 0, 0, kdb, 0, IF_BFP) - F(0xb348, KXBR, RRE, Z, x2h, x2l, x1, 0, kxb, 0, IF_BFP) + F(0xb348, KXBR, RRE, Z, x1, x2, 0, 0, kxb, 0, IF_BFP) F(0xed08, KEB, RXE, Z, e1, m2_32u, 0, 0, keb, 0, IF_BFP) F(0xed18, KDB, RXE, Z, f1, m2_64, 0, 0, kdb, 0, IF_BFP) /* COMPARE IMMEDIATE */ @@ -299,10 +299,10 @@ /* CONVERT TO FIXED */ F(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0, IF_BFP) F(0xb399, CFDBR, RRF_e, Z, 0, f2, new, r1_32, cfdb, 0, IF_BFP) - F(0xb39a, CFXBR, RRF_e, Z, x2h, x2l, new, r1_32, cfxb, 0, IF_BFP) + F(0xb39a, CFXBR, RRF_e, Z, 0, x2, new, r1_32, cfxb, 0, IF_BFP) F(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0, IF_BFP) F(0xb3a9, CGDBR, RRF_e, Z, 0, f2, r1, 0, cgdb, 0, IF_BFP) - F(0xb3aa, CGXBR, RRF_e, Z, x2h, x2l, r1, 0, cgxb, 0, IF_BFP) + F(0xb3aa, CGXBR, RRF_e, Z, 0, x2, r1, 0, cgxb, 0, IF_BFP) /* CONVERT FROM FIXED */ F(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0, IF_BFP) F(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, new, f1, cdgb, 0, IF_BFP) @@ -313,10 +313,10 @@ /* CONVERT TO LOGICAL */ F(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP) F(0xb39d, CLFDBR, RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP) - F(0xb39e, CLFXBR, RRF_e, FPE, x2h, x2l, new, r1_32, clfxb, 0, IF_BFP) + F(0xb39e, CLFXBR, RRF_e, FPE, 0, x2, new, r1_32, clfxb, 0, IF_BFP) F(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0, IF_BFP) F(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2, r1, 0, clgdb, 0, IF_BFP) - F(0xb3ae, CLGXBR, RRF_e, FPE, x2h, x2l, r1, 0, clgxb, 0, IF_BFP) + F(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2, r1, 0, clgxb, 0, IF_BFP) /* CONVERT FROM LOGICAL */ F(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP) F(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP) @@ -343,7 +343,7 @@ C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) F(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0, IF_BFP) F(0xb31d, DDBR, RRE, Z, f1, f2, new, f1, ddb, 0, IF_BFP) - F(0xb34d, DXBR, RRE, Z, x2h, x2l, x1, x1, dxb, 0, IF_BFP) + F(0xb34d, DXBR, RRE, Z, x1, x2, new_x, x1, dxb, 0, IF_BFP) F(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0, IF_BFP) F(0xed1d, DDB, RXE, Z, f1, m2_64, new, f1, ddb, 0, IF_BFP) /* DIVIDE LOGICAL */ @@ -597,7 +597,7 @@ /* LOAD FP INTEGER */ F(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0, IF_BFP) F(0xb35f, FIDBR, RRF_e, Z, 0, f2, new, f1, fidb, 0, IF_BFP) - F(0xb347, FIXBR, RRF_e, Z, x2h, x2l, new_x, x1, fixb, 0, IF_BFP) + F(0xb347, FIXBR, RRF_e, Z, 0, x2, new_x, x1, fixb, 0, IF_BFP) /* LOAD LENGTHENED */ F(0xb304, LDEBR, RRE, Z, 0, e2, new, f1, ldeb, 0, IF_BFP) @@ -610,8 +610,8 @@ F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1) /* LOAD ROUNDED */ F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP) - F(0xb345, LDXBR, RRF_e, Z, x2h, x2l, new, f1, ldxb, 0, IF_BFP) - F(0xb346, LEXBR, RRF_e, Z, x2h, x2l, new, e1, lexb, 0, IF_BFP) + F(0xb345, LDXBR, RRF_e, Z, 0, x2, new, f1, ldxb, 0, IF_BFP) + F(0xb346, LEXBR, RRF_e, Z, 0, x2, new, e1, lexb, 0, IF_BFP) /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) @@ -666,7 +666,7 @@ C(0xe384, MG, RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0) F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP) F(0xb31c, MDBR, RRE, Z, f1, f2, new, f1, mdb, 0, IF_BFP) - F(0xb34c, MXBR, RRE, Z, x2h, x2l, x1, x1, mxb, 0, IF_BFP) + F(0xb34c, MXBR, RRE, Z, x1, x2, new_x, x1, mxb, 0, IF_BFP) F(0xb30c, MDEBR, RRE, Z, f1, e2, new, f1, mdeb, 0, IF_BFP) F(0xb307, MXDBR, RRE, Z, 0, f2, x1, x1, mxdb, 0, IF_BFP) F(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0, IF_BFP) @@ -835,7 +835,7 @@ /* SQUARE ROOT */ F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP) - F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_x, x1, sqxb, 0, IF_BFP) + F(0xb316, SQXBR, RRE, Z, 0, x2, new_x, x1, sqxb, 0, IF_BFP) F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP) F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) @@ -913,7 +913,7 @@ C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) F(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32, IF_BFP) F(0xb31b, SDBR, RRE, Z, f1, f2, new, f1, sdb, f64, IF_BFP) - F(0xb34b, SXBR, RRE, Z, x2h, x2l, x1, x1, sxb, f128, IF_BFP) + F(0xb34b, SXBR, RRE, Z, x1, x2, new_x, x1, sxb, f128, IF_BFP) F(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32, IF_BFP) F(0xed1b, SDB, RXE, Z, f1, m2_64, new, f1, sdb, f64, IF_BFP) /* SUBTRACT HALFWORD */ @@ -957,7 +957,7 @@ /* TEST DATA CLASS */ F(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0, IF_BFP) F(0xed11, TCDB, RXE, Z, f1, a2, 0, 0, tcdb, 0, IF_BFP) - F(0xed12, TCXB, RXE, Z, 0, a2, x1, 0, tcxb, 0, IF_BFP) + F(0xed12, TCXB, RXE, Z, x1, a2, 0, 0, tcxb, 0, IF_BFP) /* TEST DECIMAL */ C(0xebc0, TP, RSL, E2, la1, 0, 0, 0, tp, 0) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 0a750a5467..d422a1e62b 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -305,6 +305,18 @@ static TCGv_i64 load_freg32_i64(int reg) return r; } +static TCGv_i128 load_freg_128(int reg) +{ + TCGv_i64 h = load_freg(reg); + TCGv_i64 l = load_freg(reg + 2); + TCGv_i128 r = tcg_temp_new_i128(); + + tcg_gen_concat_i64_i128(r, l, h); + tcg_temp_free_i64(h); + tcg_temp_free_i64(l); + return r; +} + static void store_reg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(regs[reg], v); @@ -1103,7 +1115,7 @@ typedef struct { bool g_out, g_out2, g_in1, g_in2; TCGv_i64 out, out2, in1, in2; TCGv_i64 addr1; - TCGv_i128 out_128; + TCGv_i128 out_128, in1_128, in2_128; } DisasOps; /* Instructions can place constraints on their operands, raising specification @@ -1462,7 +1474,7 @@ static DisasJumpType op_adb(DisasContext *s, DisasOps *o) static DisasJumpType op_axb(DisasContext *s, DisasOps *o) { - gen_helper_axb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_axb(o->out_128, cpu_env, o->in1_128, o->in2_128); return DISAS_NEXT; } @@ -1778,7 +1790,7 @@ static DisasJumpType op_cdb(DisasContext *s, DisasOps *o) static DisasJumpType op_cxb(DisasContext *s, DisasOps *o) { - gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_cxb(cc_op, cpu_env, o->in1_128, o->in2_128); set_cc_static(s); return DISAS_NEXT; } @@ -1841,7 +1853,7 @@ static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_cfxb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); set_cc_static(s); return DISAS_NEXT; @@ -1880,7 +1892,7 @@ static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_cgxb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); set_cc_static(s); return DISAS_NEXT; @@ -1919,7 +1931,7 @@ static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_clfxb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); set_cc_static(s); return DISAS_NEXT; @@ -1958,7 +1970,7 @@ static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_clgxb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); set_cc_static(s); return DISAS_NEXT; @@ -2445,7 +2457,7 @@ static DisasJumpType op_ddb(DisasContext *s, DisasOps *o) static DisasJumpType op_dxb(DisasContext *s, DisasOps *o) { - gen_helper_dxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_dxb(o->out_128, cpu_env, o->in1_128, o->in2_128); return DISAS_NEXT; } @@ -2550,7 +2562,7 @@ static DisasJumpType op_fixb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_fixb(o->out_128, cpu_env, o->in1, o->in2, m34); + gen_helper_fixb(o->out_128, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -2769,7 +2781,7 @@ static DisasJumpType op_kdb(DisasContext *s, DisasOps *o) static DisasJumpType op_kxb(DisasContext *s, DisasOps *o) { - gen_helper_kxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_kxb(cc_op, cpu_env, o->in1_128, o->in2_128); set_cc_static(s); return DISAS_NEXT; } @@ -2843,7 +2855,7 @@ static DisasJumpType op_ldxb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_ldxb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -2855,7 +2867,7 @@ static DisasJumpType op_lexb(DisasContext *s, DisasOps *o) if (!m34) { return DISAS_NORETURN; } - gen_helper_lexb(o->out, cpu_env, o->in1, o->in2, m34); + gen_helper_lexb(o->out, cpu_env, o->in2_128, m34); tcg_temp_free_i32(m34); return DISAS_NEXT; } @@ -3584,13 +3596,13 @@ static DisasJumpType op_mdb(DisasContext *s, DisasOps *o) static DisasJumpType op_mxb(DisasContext *s, DisasOps *o) { - gen_helper_mxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_mxb(o->out_128, cpu_env, o->in1_128, o->in2_128); return DISAS_NEXT; } static DisasJumpType op_mxdb(DisasContext *s, DisasOps *o) { - gen_helper_mxdb(o->out_128, cpu_env, o->out, o->out2, o->in2); + gen_helper_mxdb(o->out_128, cpu_env, o->in1_128, o->in2); return DISAS_NEXT; } @@ -4055,7 +4067,7 @@ static DisasJumpType op_sdb(DisasContext *s, DisasOps *o) static DisasJumpType op_sxb(DisasContext *s, DisasOps *o) { - gen_helper_sxb(o->out_128, cpu_env, o->out, o->out2, o->in1, o->in2); + gen_helper_sxb(o->out_128, cpu_env, o->in1_128, o->in2_128); return DISAS_NEXT; } @@ -4073,7 +4085,7 @@ static DisasJumpType op_sqdb(DisasContext *s, DisasOps *o) static DisasJumpType op_sqxb(DisasContext *s, DisasOps *o) { - gen_helper_sqxb(o->out_128, cpu_env, o->in1, o->in2); + gen_helper_sqxb(o->out_128, cpu_env, o->in2_128); return DISAS_NEXT; } @@ -4852,7 +4864,7 @@ static DisasJumpType op_tcdb(DisasContext *s, DisasOps *o) static DisasJumpType op_tcxb(DisasContext *s, DisasOps *o) { - gen_helper_tcxb(cc_op, cpu_env, o->out, o->out2, o->in2); + gen_helper_tcxb(cc_op, cpu_env, o->in1_128, o->in2); set_cc_static(s); return DISAS_NEXT; } @@ -5387,8 +5399,6 @@ static void prep_new_P(DisasContext *s, DisasOps *o) static void prep_new_x(DisasContext *s, DisasOps *o) { - o->out = tcg_temp_new_i64(); - o->out2 = tcg_temp_new_i64(); o->out_128 = tcg_temp_new_i128(); } #define SPEC_prep_new_x 0 @@ -5411,10 +5421,7 @@ static void prep_r1_P(DisasContext *s, DisasOps *o) static void prep_x1(DisasContext *s, DisasOps *o) { - o->out = load_freg(get_field(s, r1)); - o->out2 = load_freg(get_field(s, r1) + 2); - o->out_128 = tcg_temp_new_i128(); - tcg_gen_concat_i64_i128(o->out_128, o->out2, o->out); + o->out_128 = load_freg_128(get_field(s, r1)); } #define SPEC_prep_x1 SPEC_r1_f128 @@ -5513,6 +5520,11 @@ static void wout_x1(DisasContext *s, DisasOps *o) { int f1 = get_field(s, r1); + /* Split out_128 into out+out2 for cout_f128. */ + tcg_debug_assert(o->out == NULL); + o->out = tcg_temp_new_i64(); + o->out2 = tcg_temp_new_i64(); + tcg_gen_extr_i128_i64(o->out2, o->out, o->out_128); store_freg(f1, o->out); store_freg(f1 + 2, o->out2); @@ -5755,6 +5767,12 @@ static void in1_f1(DisasContext *s, DisasOps *o) } #define SPEC_in1_f1 0 +static void in1_x1(DisasContext *s, DisasOps *o) +{ + o->in1_128 = load_freg_128(get_field(s, r1)); +} +#define SPEC_in1_x1 SPEC_r1_f128 + /* Load the high double word of an extended (128-bit) format FP number */ static void in1_x2h(DisasContext *s, DisasOps *o) { @@ -5964,6 +5982,12 @@ static void in2_f2(DisasContext *s, DisasOps *o) } #define SPEC_in2_f2 0 +static void in2_x2(DisasContext *s, DisasOps *o) +{ + o->in2_128 = load_freg_128(get_field(s, r2)); +} +#define SPEC_in2_x2 SPEC_r2_f128 + /* Load the low double word of an extended (128-bit) format FP number */ static void in2_x2l(DisasContext *s, DisasOps *o) { @@ -6592,6 +6616,12 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) if (o.out_128) { tcg_temp_free_i128(o.out_128); } + if (o.in1_128) { + tcg_temp_free_i128(o.in1_128); + } + if (o.in2_128) { + tcg_temp_free_i128(o.in2_128); + } /* io should be the last instruction in tb when icount is enabled */ if (unlikely(icount && ret == DISAS_NEXT)) { ret = DISAS_TOO_MANY; From 1fcd84fa0d610c1215cced54e64046a47148a388 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Nov 2022 13:54:35 +1100 Subject: [PATCH 504/814] target/s390x: Use tcg_gen_atomic_cmpxchg_i128 for CDSG Acked-by: Ilya Leoshkevich Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 -- target/s390x/tcg/insn-data.h.inc | 2 +- target/s390x/tcg/mem_helper.c | 52 ------------------------------ target/s390x/tcg/translate.c | 55 +++++++++++++++++++------------- 4 files changed, 33 insertions(+), 78 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index bccd3bfca6..341bc51ec2 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -35,8 +35,6 @@ DEF_HELPER_3(cxgb, i128, env, s64, i32) DEF_HELPER_3(celgb, i64, env, i64, i32) DEF_HELPER_3(cdlgb, i64, env, i64, i32) DEF_HELPER_3(cxlgb, i128, env, i64, i32) -DEF_HELPER_4(cdsg, void, env, i64, i32, i32) -DEF_HELPER_4(cdsg_parallel, void, env, i64, i32, i32) DEF_HELPER_4(csst, i32, env, i32, i64, i64) DEF_HELPER_4(csst_parallel, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc index 893f4b48db..9d2d35f084 100644 --- a/target/s390x/tcg/insn-data.h.inc +++ b/target/s390x/tcg/insn-data.h.inc @@ -276,7 +276,7 @@ /* COMPARE DOUBLE AND SWAP */ D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEUQ) - C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) + C(0xeb3e, CDSG, RSY_a, Z, la2, r3_D64, 0, r1_D64, cdsg, 0) /* COMPARE AND SWAP AND STORE */ C(0xc802, CSST, SSF, CASS, la1, a2, 0, 0, csst, 0) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 49969abda7..d6725fd18c 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -1771,58 +1771,6 @@ uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2, return cc; } -void HELPER(cdsg)(CPUS390XState *env, uint64_t addr, - uint32_t r1, uint32_t r3) -{ - uintptr_t ra = GETPC(); - Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]); - Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]); - Int128 oldv; - uint64_t oldh, oldl; - bool fail; - - check_alignment(env, addr, 16, ra); - - oldh = cpu_ldq_data_ra(env, addr + 0, ra); - oldl = cpu_ldq_data_ra(env, addr + 8, ra); - - oldv = int128_make128(oldl, oldh); - fail = !int128_eq(oldv, cmpv); - if (fail) { - newv = oldv; - } - - cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra); - cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra); - - env->cc_op = fail; - env->regs[r1] = int128_gethi(oldv); - env->regs[r1 + 1] = int128_getlo(oldv); -} - -void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr, - uint32_t r1, uint32_t r3) -{ - uintptr_t ra = GETPC(); - Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]); - Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]); - int mem_idx; - MemOpIdx oi; - Int128 oldv; - bool fail; - - assert(HAVE_CMPXCHG128); - - mem_idx = cpu_mmu_index(env, false); - oi = make_memop_idx(MO_TE | MO_128 | MO_ALIGN, mem_idx); - oldv = cpu_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra); - fail = !int128_eq(oldv, cmpv); - - env->cc_op = fail; - env->regs[r1] = int128_gethi(oldv); - env->regs[r1 + 1] = int128_getlo(oldv); -} - static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2, bool parallel) { diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index d422a1e62b..9ea28b3e52 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -2224,31 +2224,25 @@ static DisasJumpType op_cs(DisasContext *s, DisasOps *o) static DisasJumpType op_cdsg(DisasContext *s, DisasOps *o) { int r1 = get_field(s, r1); - int r3 = get_field(s, r3); - int d2 = get_field(s, d2); - int b2 = get_field(s, b2); - DisasJumpType ret = DISAS_NEXT; - TCGv_i64 addr; - TCGv_i32 t_r1, t_r3; - /* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */ - addr = get_address(s, 0, b2, d2); - t_r1 = tcg_const_i32(r1); - t_r3 = tcg_const_i32(r3); - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_helper_cdsg(cpu_env, addr, t_r1, t_r3); - } else if (HAVE_CMPXCHG128) { - gen_helper_cdsg_parallel(cpu_env, addr, t_r1, t_r3); - } else { - gen_helper_exit_atomic(cpu_env); - ret = DISAS_NORETURN; - } - tcg_temp_free_i64(addr); - tcg_temp_free_i32(t_r1); - tcg_temp_free_i32(t_r3); + o->out_128 = tcg_temp_new_i128(); + tcg_gen_concat_i64_i128(o->out_128, regs[r1 + 1], regs[r1]); - set_cc_static(s); - return ret; + /* Note out (R1:R1+1) = expected value and in2 (R3:R3+1) = new value. */ + tcg_gen_atomic_cmpxchg_i128(o->out_128, o->addr1, o->out_128, o->in2_128, + get_mem_index(s), MO_BE | MO_128 | MO_ALIGN); + + /* + * Extract result into cc_dst:cc_src, compare vs the expected value + * in the as yet unmodified input registers, then update CC_OP. + */ + tcg_gen_extr_i128_i64(cc_src, cc_dst, o->out_128); + tcg_gen_xor_i64(cc_dst, cc_dst, regs[r1]); + tcg_gen_xor_i64(cc_src, cc_src, regs[r1 + 1]); + tcg_gen_or_i64(cc_dst, cc_dst, cc_src); + set_cc_nz_u64(s, cc_dst); + + return DISAS_NEXT; } static DisasJumpType op_csst(DisasContext *s, DisasOps *o) @@ -5488,6 +5482,13 @@ static void wout_r1_D32(DisasContext *s, DisasOps *o) } #define SPEC_wout_r1_D32 SPEC_r1_even +static void wout_r1_D64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s, r1); + tcg_gen_extr_i128_i64(regs[r1 + 1], regs[r1], o->out_128); +} +#define SPEC_wout_r1_D64 SPEC_r1_even + static void wout_r3_P32(DisasContext *s, DisasOps *o) { int r3 = get_field(s, r3); @@ -5935,6 +5936,14 @@ static void in2_r3(DisasContext *s, DisasOps *o) } #define SPEC_in2_r3 0 +static void in2_r3_D64(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s, r3); + o->in2_128 = tcg_temp_new_i128(); + tcg_gen_concat_i64_i128(o->in2_128, regs[r3 + 1], regs[r3]); +} +#define SPEC_in2_r3_D64 SPEC_r3_even + static void in2_r3_sr32(DisasContext *s, DisasOps *o) { o->in2 = tcg_temp_new_i64(); From b5deff74d1b1cb33b65a6c8db44fc87e972b53f7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 10 Nov 2022 18:12:09 +1000 Subject: [PATCH 505/814] target/s390x: Implement CC_OP_NZ in gen_op_calc_cc This case is trivial to implement inline. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- target/s390x/tcg/translate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 9ea28b3e52..ac5bd98f04 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -625,6 +625,9 @@ static void gen_op_calc_cc(DisasContext *s) /* env->cc_op already is the cc value */ break; case CC_OP_NZ: + tcg_gen_setcondi_i64(TCG_COND_NE, cc_dst, cc_dst, 0); + tcg_gen_extrl_i64_i32(cc_op, cc_dst); + break; case CC_OP_ABS_64: case CC_OP_NABS_64: case CC_OP_ABS_32: From 6218c177afb341e5a64428fcc17decbc9d6247a6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Nov 2022 15:22:15 +1100 Subject: [PATCH 506/814] target/i386: Split out gen_cmpxchg8b, gen_cmpxchg16b 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 --- target/i386/tcg/translate.c | 48 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 7e0b2a709a..a82131d635 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2993,6 +2993,34 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align) #include "emit.c.inc" #include "decode-new.c.inc" +static void gen_cmpxchg8b(DisasContext *s, CPUX86State *env, int modrm) +{ + gen_lea_modrm(env, s, modrm); + + if ((s->prefix & PREFIX_LOCK) && + (tb_cflags(s->base.tb) & CF_PARALLEL)) { + gen_helper_cmpxchg8b(cpu_env, s->A0); + } else { + gen_helper_cmpxchg8b_unlocked(cpu_env, s->A0); + } + set_cc_op(s, CC_OP_EFLAGS); +} + +#ifdef TARGET_X86_64 +static void gen_cmpxchg16b(DisasContext *s, CPUX86State *env, int modrm) +{ + gen_lea_modrm(env, s, modrm); + + if ((s->prefix & PREFIX_LOCK) && + (tb_cflags(s->base.tb) & CF_PARALLEL)) { + gen_helper_cmpxchg16b(cpu_env, s->A0); + } else { + gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0); + } + set_cc_op(s, CC_OP_EFLAGS); +} +#endif + /* convert one instruction. s->base.is_jmp is set if the translation must be stopped. Return the next pc value */ static bool disas_insn(DisasContext *s, CPUState *cpu) @@ -3844,28 +3872,14 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) { goto illegal_op; } - gen_lea_modrm(env, s, modrm); - if ((s->prefix & PREFIX_LOCK) && - (tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_helper_cmpxchg16b(cpu_env, s->A0); - } else { - gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0); - } - set_cc_op(s, CC_OP_EFLAGS); + gen_cmpxchg16b(s, env, modrm); break; } -#endif +#endif if (!(s->cpuid_features & CPUID_CX8)) { goto illegal_op; } - gen_lea_modrm(env, s, modrm); - if ((s->prefix & PREFIX_LOCK) && - (tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_helper_cmpxchg8b(cpu_env, s->A0); - } else { - gen_helper_cmpxchg8b_unlocked(cpu_env, s->A0); - } - set_cc_op(s, CC_OP_EFLAGS); + gen_cmpxchg8b(s, env, modrm); break; case 7: /* RDSEED */ From 326ad06cf5b2cf6f4ed7ca635269e89fd189e1a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Nov 2022 15:59:03 +1100 Subject: [PATCH 507/814] target/i386: Inline cmpxchg8b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use tcg_gen_atomic_cmpxchg_i64 for the atomic case, and tcg_gen_nonatomic_cmpxchg_i64 otherwise. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/helper.h | 2 -- target/i386/tcg/mem_helper.c | 57 ------------------------------------ target/i386/tcg/translate.c | 54 ++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 64 deletions(-) diff --git a/target/i386/helper.h b/target/i386/helper.h index b7de5429ef..2df8049f91 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -66,8 +66,6 @@ DEF_HELPER_1(rsm, void, env) #endif /* !CONFIG_USER_ONLY */ DEF_HELPER_2(into, void, env, int) -DEF_HELPER_2(cmpxchg8b_unlocked, void, env, tl) -DEF_HELPER_2(cmpxchg8b, void, env, tl) #ifdef TARGET_X86_64 DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl) DEF_HELPER_2(cmpxchg16b, void, env, tl) diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c index e3cdafd2d4..814786bb87 100644 --- a/target/i386/tcg/mem_helper.c +++ b/target/i386/tcg/mem_helper.c @@ -27,63 +27,6 @@ #include "tcg/tcg.h" #include "helper-tcg.h" -void helper_cmpxchg8b_unlocked(CPUX86State *env, target_ulong a0) -{ - uintptr_t ra = GETPC(); - uint64_t oldv, cmpv, newv; - int eflags; - - eflags = cpu_cc_compute_all(env, CC_OP); - - cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]); - newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]); - - oldv = cpu_ldq_data_ra(env, a0, ra); - newv = (cmpv == oldv ? newv : oldv); - /* always do the store */ - cpu_stq_data_ra(env, a0, newv, ra); - - if (oldv == cmpv) { - eflags |= CC_Z; - } else { - env->regs[R_EAX] = (uint32_t)oldv; - env->regs[R_EDX] = (uint32_t)(oldv >> 32); - eflags &= ~CC_Z; - } - CC_SRC = eflags; -} - -void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) -{ -#ifdef CONFIG_ATOMIC64 - uint64_t oldv, cmpv, newv; - int eflags; - - eflags = cpu_cc_compute_all(env, CC_OP); - - cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]); - newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]); - - { - uintptr_t ra = GETPC(); - int mem_idx = cpu_mmu_index(env, false); - MemOpIdx oi = make_memop_idx(MO_TEUQ, mem_idx); - oldv = cpu_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra); - } - - if (oldv == cmpv) { - eflags |= CC_Z; - } else { - env->regs[R_EAX] = (uint32_t)oldv; - env->regs[R_EDX] = (uint32_t)(oldv >> 32); - eflags &= ~CC_Z; - } - CC_SRC = eflags; -#else - cpu_loop_exit_atomic(env_cpu(env), GETPC()); -#endif /* CONFIG_ATOMIC64 */ -} - #ifdef TARGET_X86_64 void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0) { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a82131d635..b542b084a6 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2995,15 +2995,59 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align) static void gen_cmpxchg8b(DisasContext *s, CPUX86State *env, int modrm) { + TCGv_i64 cmp, val, old; + TCGv Z; + gen_lea_modrm(env, s, modrm); - if ((s->prefix & PREFIX_LOCK) && - (tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_helper_cmpxchg8b(cpu_env, s->A0); + cmp = tcg_temp_new_i64(); + val = tcg_temp_new_i64(); + old = tcg_temp_new_i64(); + + /* Construct the comparison values from the register pair. */ + tcg_gen_concat_tl_i64(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]); + tcg_gen_concat_tl_i64(val, cpu_regs[R_EBX], cpu_regs[R_ECX]); + + /* 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); } else { - gen_helper_cmpxchg8b_unlocked(cpu_env, s->A0); + tcg_gen_nonatomic_cmpxchg_i64(old, s->A0, cmp, val, + s->mem_index, MO_TEUQ); } - set_cc_op(s, CC_OP_EFLAGS); + tcg_temp_free_i64(val); + + /* Set tmp0 to match 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); + tcg_temp_free_i64(cmp); + + /* + * Extract the result values for the register pair. + * For 32-bit, we may do this unconditionally, because on success (Z=1), + * the old value matches the previous value in EDX:EAX. For x86_64, + * the store must be conditional, because we must leave the source + * registers unchanged on success, and zero-extend the writeback + * on failure (Z=0). + */ + if (TARGET_LONG_BITS == 32) { + tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], old); + } else { + TCGv zero = tcg_constant_tl(0); + + tcg_gen_extr_i64_tl(s->T0, s->T1, old); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EAX], Z, zero, + s->T0, cpu_regs[R_EAX]); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EDX], Z, zero, + s->T1, cpu_regs[R_EDX]); + } + tcg_temp_free_i64(old); + + /* Update Z. */ + gen_compute_eflags(s); + tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, Z, ctz32(CC_Z), 1); + tcg_temp_free(Z); } #ifdef TARGET_X86_64 From 5f0dd8cd33cb6c753ed4435e13bd0622a38a9967 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 9 Nov 2022 23:53:10 +1100 Subject: [PATCH 508/814] target/i386: Inline cmpxchg16b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use tcg_gen_atomic_cmpxchg_i128 for the atomic case, and tcg_gen_qemu_ld/st_i128 otherwise. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/helper.h | 4 --- target/i386/tcg/mem_helper.c | 69 ------------------------------------ target/i386/tcg/translate.c | 44 ++++++++++++++++++++--- 3 files changed, 39 insertions(+), 78 deletions(-) diff --git a/target/i386/helper.h b/target/i386/helper.h index 2df8049f91..e627a93107 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -66,10 +66,6 @@ DEF_HELPER_1(rsm, void, env) #endif /* !CONFIG_USER_ONLY */ DEF_HELPER_2(into, void, env, int) -#ifdef TARGET_X86_64 -DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl) -DEF_HELPER_2(cmpxchg16b, void, env, tl) -#endif DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_1(rechecking_single_step, void, env) DEF_HELPER_1(cpuid, void, env) diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c index 814786bb87..3ef84e90d9 100644 --- a/target/i386/tcg/mem_helper.c +++ b/target/i386/tcg/mem_helper.c @@ -27,75 +27,6 @@ #include "tcg/tcg.h" #include "helper-tcg.h" -#ifdef TARGET_X86_64 -void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0) -{ - uintptr_t ra = GETPC(); - Int128 oldv, cmpv, newv; - uint64_t o0, o1; - int eflags; - bool success; - - if ((a0 & 0xf) != 0) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } - eflags = cpu_cc_compute_all(env, CC_OP); - - cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]); - newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]); - - o0 = cpu_ldq_data_ra(env, a0 + 0, ra); - o1 = cpu_ldq_data_ra(env, a0 + 8, ra); - - oldv = int128_make128(o0, o1); - success = int128_eq(oldv, cmpv); - if (!success) { - newv = oldv; - } - - cpu_stq_data_ra(env, a0 + 0, int128_getlo(newv), ra); - cpu_stq_data_ra(env, a0 + 8, int128_gethi(newv), ra); - - if (success) { - eflags |= CC_Z; - } else { - env->regs[R_EAX] = int128_getlo(oldv); - env->regs[R_EDX] = int128_gethi(oldv); - eflags &= ~CC_Z; - } - CC_SRC = eflags; -} - -void helper_cmpxchg16b(CPUX86State *env, target_ulong a0) -{ - uintptr_t ra = GETPC(); - - if ((a0 & 0xf) != 0) { - raise_exception_ra(env, EXCP0D_GPF, ra); - } else if (HAVE_CMPXCHG128) { - int eflags = cpu_cc_compute_all(env, CC_OP); - - Int128 cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]); - Int128 newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]); - - int mem_idx = cpu_mmu_index(env, false); - MemOpIdx oi = make_memop_idx(MO_TE | MO_128 | MO_ALIGN, mem_idx); - Int128 oldv = cpu_atomic_cmpxchgo_le_mmu(env, a0, cmpv, newv, oi, ra); - - if (int128_eq(oldv, cmpv)) { - eflags |= CC_Z; - } else { - env->regs[R_EAX] = int128_getlo(oldv); - env->regs[R_EDX] = int128_gethi(oldv); - eflags &= ~CC_Z; - } - CC_SRC = eflags; - } else { - cpu_loop_exit_atomic(env_cpu(env), ra); - } -} -#endif - void helper_boundw(CPUX86State *env, target_ulong a0, int v) { int low, high; diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index b542b084a6..9d9392b009 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3053,15 +3053,49 @@ static void gen_cmpxchg8b(DisasContext *s, CPUX86State *env, int modrm) #ifdef TARGET_X86_64 static void gen_cmpxchg16b(DisasContext *s, CPUX86State *env, int modrm) { + MemOp mop = MO_TE | MO_128 | MO_ALIGN; + TCGv_i64 t0, t1; + TCGv_i128 cmp, val; + gen_lea_modrm(env, s, modrm); - if ((s->prefix & PREFIX_LOCK) && - (tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_helper_cmpxchg16b(cpu_env, s->A0); + cmp = tcg_temp_new_i128(); + val = tcg_temp_new_i128(); + tcg_gen_concat_i64_i128(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]); + tcg_gen_concat_i64_i128(val, cpu_regs[R_EBX], cpu_regs[R_ECX]); + + /* Only require atomic with LOCK; non-parallel handled in generator. */ + if (s->prefix & PREFIX_LOCK) { + tcg_gen_atomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop); } else { - gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0); + tcg_gen_nonatomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop); } - set_cc_op(s, CC_OP_EFLAGS); + + tcg_gen_extr_i128_i64(s->T0, s->T1, val); + tcg_temp_free_i128(cmp); + tcg_temp_free_i128(val); + + /* Determine success after the fact. */ + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + tcg_gen_xor_i64(t0, s->T0, cpu_regs[R_EAX]); + tcg_gen_xor_i64(t1, s->T1, cpu_regs[R_EDX]); + tcg_gen_or_i64(t0, t0, t1); + tcg_temp_free_i64(t1); + + /* Update Z. */ + gen_compute_eflags(s); + tcg_gen_setcondi_i64(TCG_COND_EQ, t0, t0, 0); + tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, t0, ctz32(CC_Z), 1); + tcg_temp_free_i64(t0); + + /* + * Extract the result values for the register pair. We may do this + * unconditionally, because on success (Z=1), the old value matches + * the previous value in RDX:RAX. + */ + tcg_gen_mov_i64(cpu_regs[R_EAX], s->T0); + tcg_gen_mov_i64(cpu_regs[R_EDX], s->T1); } #endif From a2495ede07498ee36b18b03e7038ba30c9871bb2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Feb 2023 17:16:31 +0000 Subject: [PATCH 509/814] tcg/aarch64: Fix patching of LDR in tb_target_set_jmp_target 'offset' should be bits [23:5] of LDR instruction, rather than [4:0]. Fixes: d59d83a1c388 ("tcg/aarch64: Reorg goto_tb implementation") Reviewed-by: Zenghui Yu Reported-by: Zenghui Yu Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index fde3b30ad1..a091326f84 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1914,7 +1914,7 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, ptrdiff_t i_offset = i_addr - jmp_rx; /* Note that we asserted this in range in tcg_out_goto_tb. */ - insn = deposit32(I3305_LDR | TCG_REG_TMP, 0, 5, i_offset >> 2); + insn = deposit32(I3305_LDR | TCG_REG_TMP, 5, 19, i_offset >> 2); } qatomic_set((uint32_t *)jmp_rw, insn); flush_idcache_range(jmp_rx, jmp_rw, 4); From 7661a7ab53a19e6541c2661ddb27d7ca4e1dfa31 Mon Sep 17 00:00:00 2001 From: Murilo Opsfelder Araujo Date: Mon, 8 Aug 2022 21:24:50 -0300 Subject: [PATCH 510/814] tests/migration: add sysprof-capture-4 as dependency for stress binary `make tests/migration/stress` fails with: FAILED: tests/migration/stress cc -m64 -mlittle-endian -o tests/migration/stress tests/migration/stress.p/stress.c.o -Wl,--as-needed -Wl,--no-undefined -pie -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -static -pthread -Wl,--start-group -lgthread-2.0 -lglib-2.0 -Wl,--end-group /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gutils.c.o): in function `.annobin_gutils.c': (.text+0x3b4): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/bin/ld: (.text+0x178): warning: Using 'getpwnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/bin/ld: (.text+0x1bc): warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gthread.c.o):(.toc+0x0): undefined reference to `sysprof_clock' /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gtrace.c.o): in function `.annobin_gtrace.c': (.text+0x24): undefined reference to `sysprof_collector_mark_vprintf' /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gtrace.c.o): in function `g_trace_define_int64_counter': (.text+0x8c): undefined reference to `sysprof_collector_request_counters' /usr/bin/ld: (.text+0x108): undefined reference to `sysprof_collector_define_counters' /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gtrace.c.o): in function `g_trace_set_int64_counter': (.text+0x23c): undefined reference to `sysprof_collector_set_counters' /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gspawn.c.o):(.toc+0x0): undefined reference to `sysprof_clock' /usr/bin/ld: /usr/lib/gcc/ppc64le-redhat-linux/11/../../../../lib64/libglib-2.0.a(gmain.c.o):(.toc+0x0): undefined reference to `sysprof_clock' collect2: error: ld returned 1 exit status ninja: build stopped: subcommand failed. make: *** [Makefile:162: run-ninja] Error 1 Add sysprof-capture-4 as dependency for stress binary. Tested on: - CentOS Stream 9 ppc64le - Fedora 36 x86_64 Signed-off-by: Murilo Opsfelder Araujo Reviewed-by: Daniel Henrique Barboza Reviewed-by: Juan Quintela Message-Id: <20220809002451.91541-2-muriloo@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- tests/migration/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/migration/meson.build b/tests/migration/meson.build index f215ee7d3a..dd562355a1 100644 --- a/tests/migration/meson.build +++ b/tests/migration/meson.build @@ -1,7 +1,9 @@ +sysprof = dependency('sysprof-capture-4', required: false) + stress = executable( 'stress', files('stress.c'), - dependencies: [glib], + dependencies: [glib, sysprof], link_args: ['-static'], build_by_default: false, ) From 8763196c2c1aa4128040964c31529936932754e0 Mon Sep 17 00:00:00 2001 From: Murilo Opsfelder Araujo Date: Mon, 8 Aug 2022 21:24:51 -0300 Subject: [PATCH 511/814] tests/migration: add support for ppc64le for guestperf.py Add support for ppc64le for guestperf.py. On ppc, console is usually hvc0 and serial device for pseries machine is spapr-vty. Signed-off-by: Murilo Opsfelder Araujo Reviewed-by: Daniel Henrique Barboza Reviewed-by: Juan Quintela Message-Id: <20220809002451.91541-3-muriloo@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- tests/migration/guestperf/engine.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index 59fca2c70b..cc06fac592 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -281,6 +281,26 @@ class Engine(object): resp = src.command("stop") paused = True + def _is_ppc64le(self): + _, _, _, _, machine = os.uname() + if machine == "ppc64le": + return True + return False + + def _get_guest_console_args(self): + if self._is_ppc64le(): + return "console=hvc0" + else: + return "console=ttyS0" + + def _get_qemu_serial_args(self): + if self._is_ppc64le(): + return ["-chardev", "stdio,id=cdev0", + "-device", "spapr-vty,chardev=cdev0"] + else: + return ["-chardev", "stdio,id=cdev0", + "-device", "isa-serial,chardev=cdev0"] + def _get_common_args(self, hardware, tunnelled=False): args = [ "noapic", @@ -289,8 +309,10 @@ class Engine(object): "noreplace-smp", "cgroup_disable=memory", "pci=noearly", - "console=ttyS0", ] + + args.append(self._get_guest_console_args()) + if self._debug: args.append("debug") else: @@ -308,12 +330,12 @@ class Engine(object): "-kernel", self._kernel, "-initrd", self._initrd, "-append", cmdline, - "-chardev", "stdio,id=cdev0", - "-device", "isa-serial,chardev=cdev0", "-m", str((hardware._mem * 1024) + 512), "-smp", str(hardware._cpus), ] + argv.extend(self._get_qemu_serial_args()) + if self._debug: argv.extend(["-device", "sga"]) From 65133e33eb8e60f27eff6c7c669f0920adf24c16 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Tue, 17 Jan 2023 22:36:42 +0100 Subject: [PATCH 512/814] ppc/pegasos2: Improve readability of VIA south bridge creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slightly improve readability of creating the south btidge by cnamging type of a local variable to avoid some casts within function arguments which makes some lines shorter and easier to read. Also remove an unneded line break. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230117214545.5E191746369@zero.eik.bme.hu> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/pegasos2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index f46d4bf51d..1a13632ba6 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -102,7 +102,8 @@ static void pegasos2_init(MachineState *machine) CPUPPCState *env; MemoryRegion *rom = g_new(MemoryRegion, 1); PCIBus *pci_bus; - PCIDevice *dev, *via; + Object *via; + PCIDevice *dev; I2CBus *i2c_bus; const char *fwname = machine->firmware ?: PROM_FILENAME; char *filename; @@ -159,19 +160,18 @@ static void pegasos2_init(MachineState *machine) pci_bus = mv64361_get_pci_bus(pm->mv, 1); /* VIA VT8231 South Bridge (multifunction PCI device) */ - via = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), true, - TYPE_VT8231_ISA); + via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), + true, TYPE_VT8231_ISA)); object_property_add_alias(OBJECT(machine), "rtc-time", - object_resolve_path_component(OBJECT(via), - "rtc"), + object_resolve_path_component(via, "rtc"), "date"); qdev_connect_gpio_out(DEVICE(via), 0, qdev_get_gpio_in_named(pm->mv, "gpp", 31)); - dev = PCI_DEVICE(object_resolve_path_component(OBJECT(via), "ide")); + dev = PCI_DEVICE(object_resolve_path_component(via, "ide")); pci_ide_create_devs(dev); - dev = PCI_DEVICE(object_resolve_path_component(OBJECT(via), "pm")); + dev = PCI_DEVICE(object_resolve_path_component(via, "pm")); i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c")); spd_data = spd_data_generate(DDR, machine->ram_size); smbus_eeprom_init_one(i2c_bus, 0x57, spd_data); From 3f736ca9b2d66e881bee5083655fc8c208d05299 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 6 Jan 2023 12:39:27 +0100 Subject: [PATCH 513/814] hw/pci-host/mv64361: Reuse pci_swizzle_map_irq_fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mv64361_pcihost_map_irq() is a reimplementation of pci_swizzle_map_irq_fn(). Resolve this redundancy. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: BALATON Zoltan Message-Id: <20230106113927.8603-1-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/pci-host/mv64361.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index 015b92bd5f..f43f33fbd9 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -72,11 +72,6 @@ struct MV64361PCIState { uint64_t remap[5]; }; -static int mv64361_pcihost_map_irq(PCIDevice *pci_dev, int n) -{ - return (n + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; -} - static void mv64361_pcihost_set_irq(void *opaque, int n, int level) { MV64361PCIState *s = opaque; @@ -97,7 +92,7 @@ static void mv64361_pcihost_realize(DeviceState *dev, Error **errp) g_free(name); name = g_strdup_printf("pci.%d", s->index); h->bus = pci_register_root_bus(dev, name, mv64361_pcihost_set_irq, - mv64361_pcihost_map_irq, dev, + pci_swizzle_map_irq_fn, dev, &s->mem, &s->io, 0, 4, TYPE_PCI_BUS); g_free(name); pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE); From 891d51be6fb82383f21e20b25b2bd1487c57eef9 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Wed, 25 Jan 2023 14:00:21 +0100 Subject: [PATCH 514/814] hw/ppc: Set machine->fdt in e500 machines This enables support for the 'dumpdtb' QMP/HMP command for all e500 machines. Signed-off-by: Bernhard Beschow Reviewed-by: Daniel Henrique Barboza Message-Id: <20230125130024.158721-2-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/e500.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 9fa1f8e6cf..7239993acc 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -659,9 +659,14 @@ done: if (!dry_run) { qemu_fdt_dumpdtb(fdt, fdt_size); cpu_physical_memory_write(addr, fdt, fdt_size); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + g_free(machine->fdt); + machine->fdt = fdt; + } else { + g_free(fdt); } ret = fdt_size; - g_free(fdt); out: g_free(pci_map); From 0998fcb35360557395b60678e73a9e51334a07dc Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Wed, 25 Jan 2023 14:00:22 +0100 Subject: [PATCH 515/814] hw/ppc/e500{, plat}: Drop redundant checks for presence of platform bus This is a follow-up on commit 47a0b1dff7e9 'hw/ppc/mpc8544ds: Add platform bus': Both mpc85xx boards now have a platform bus unconditionally. Signed-off-by: Bernhard Beschow Reviewed-by: Daniel Henrique Barboza Message-Id: <20230125130024.158721-3-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/e500.c | 5 ++--- hw/ppc/e500plat.c | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 7239993acc..48288c0b41 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -643,9 +643,8 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, } g_free(soc); - if (pms->pbus_dev) { - platform_bus_create_devtree(pms, fdt, mpic); - } + platform_bus_create_devtree(pms, fdt, mpic); + g_free(mpic); pmc->fixup_devtree(fdt); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 44bf874b0f..3032bd3f6d 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -46,13 +46,10 @@ static void e500plat_machine_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { PPCE500MachineState *pms = PPCE500_MACHINE(hotplug_dev); + MachineClass *mc = MACHINE_GET_CLASS(pms); - if (pms->pbus_dev) { - MachineClass *mc = MACHINE_GET_CLASS(pms); - - if (device_is_dynamic_sysbus(mc, dev)) { - platform_bus_link_device(pms->pbus_dev, SYS_BUS_DEVICE(dev)); - } + if (device_is_dynamic_sysbus(mc, dev)) { + platform_bus_link_device(pms->pbus_dev, SYS_BUS_DEVICE(dev)); } } From 4348a3aff0c8f443891dcf6764830249d0a53e86 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Wed, 25 Jan 2023 14:00:23 +0100 Subject: [PATCH 516/814] hw/ppc/e500.c: Avoid hardcoding parent device in create_devtree_etsec() The "platform" node is available through data->node, so use that instead of making assumptions about the parent device. Signed-off-by: Bernhard Beschow Reviewed-by: Daniel Henrique Barboza Message-Id: <20230125130024.158721-4-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/e500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 48288c0b41..e3b29d1d97 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -241,7 +241,7 @@ static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); - gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); + gchar *node = g_strdup_printf("%s/ethernet@%"PRIx64, data->node, mmio0); gchar *group = g_strdup_printf("%s/queue-group", node); void *fdt = data->fdt; From 4e921beac9e70962685e2cc314e770f89b341f5b Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Wed, 25 Jan 2023 14:00:24 +0100 Subject: [PATCH 517/814] hw/ppc/e500.c: Attach eSDHC unimplemented region to ccsr_addr_space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the unimplemented region move together with the CCSR address space if moved by a bootloader. Moving the CCSR address space isn't implemented yet but this patch is a preparation for it. Signed-off-by: Bernhard Beschow Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230125130024.158721-5-shentey@gmail.com> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/e500.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index e3b29d1d97..117c9c08ed 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -1022,9 +1022,13 @@ void ppce500_init(MachineState *machine) /* eSDHC */ if (pmc->has_esdhc) { - create_unimplemented_device("esdhc", - pmc->ccsrbar_base + MPC85XX_ESDHC_REGS_OFFSET, - MPC85XX_ESDHC_REGS_SIZE); + dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(dev, "name", "esdhc"); + qdev_prop_set_uint64(dev, "size", MPC85XX_ESDHC_REGS_SIZE); + s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); + memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET, + sysbus_mmio_get_region(s, 0)); /* * Compatible with: From 15b32faf6ab911ba672f0dcbf887939604b56fe9 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 27 Jan 2023 13:28:45 +0100 Subject: [PATCH 518/814] ppc/pnv/pci: Cleanup PnvPHBPecState structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused structure member 'system_memory'. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Message-Id: <20230127122848.550083-2-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- include/hw/pci-host/pnv_phb4.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index 1f3237c9d5..17aef08f91 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -173,8 +173,6 @@ struct PnvPhb4PecState { uint32_t index; uint32_t chip_id; - MemoryRegion *system_memory; - /* Nest registers, excuding per-stack */ #define PHB4_PEC_NEST_REGS_COUNT 0xf uint64_t nest_regs[PHB4_PEC_NEST_REGS_COUNT]; From f8561277fabfaef1d67f41014e8c43e0876a1b8d Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 27 Jan 2023 13:28:46 +0100 Subject: [PATCH 519/814] ppc/pnv/pci: Remove duplicate definition of PNV_PHB5_DEVICE_ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PNV_PHB5_DEVICE_ID is defined in two different headers. The definition in hw/pci-host/pnv_phb4.h was left out in a previous rework. Remaining definition is in hw/pci-host/pnv_phb.h. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Message-Id: <20230127122848.550083-3-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- include/hw/pci-host/pnv_phb4.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index 17aef08f91..761525686e 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -215,7 +215,6 @@ struct PnvPhb4PecClass { OBJECT_CHECK(PnvPhb4, (obj), TYPE_PNV_PHB5) #define PNV_PHB5_VERSION 0x000000a500000001ull -#define PNV_PHB5_DEVICE_ID 0x0652 #define TYPE_PNV_PHB5_PEC "pnv-phb5-pec" #define PNV_PHB5_PEC(obj) \ From bd34c91177461e1e60d9da042e7fdd1830ad9d61 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 27 Jan 2023 13:28:47 +0100 Subject: [PATCH 520/814] ppc/pnv/pci: Update PHB5 version register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update register value per its P10 DD2 definition. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Message-Id: <20230127122848.550083-4-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- include/hw/pci-host/pnv_phb4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index 761525686e..28d61b96c7 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -214,7 +214,7 @@ struct PnvPhb4PecClass { #define PNV_PHB5(obj) \ OBJECT_CHECK(PnvPhb4, (obj), TYPE_PNV_PHB5) -#define PNV_PHB5_VERSION 0x000000a500000001ull +#define PNV_PHB5_VERSION 0x000000a500000002ull #define TYPE_PNV_PHB5_PEC "pnv-phb5-pec" #define PNV_PHB5_PEC(obj) \ From 99bddfd01e181bbe645e73c75e98846a09c50f27 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 27 Jan 2023 13:28:48 +0100 Subject: [PATCH 521/814] ppc/pnv/pci: Fix PHB xscom registers memory region name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name is for the region mapping the PHB xscom registers. It was apparently a bad cut-and-paste from the per-stack pci xscom area just above, so we had two regions with the same name. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Message-Id: <20230127122848.550083-5-fbarrat@linux.ibm.com> Signed-off-by: Daniel Henrique Barboza --- hw/pci-host/pnv_phb4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index ccbde841fc..542f9e2932 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1497,7 +1497,7 @@ static void pnv_phb4_xscom_realize(PnvPHB4 *phb) PHB4_PEC_PCI_STK_REGS_COUNT); /* PHB pass-through */ - snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci-phb-%d", + snprintf(name, sizeof(name), "xscom-pec-%d.%d-phb-%d", pec->chip_id, pec->index, stack_no); pnv_xscom_region_init(&phb->phb_regs_mr, OBJECT(phb), &pnv_phb4_xscom_ops, phb, name, 0x40); From c009174032f65b77f625bbe0bc50f17441227527 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Fri, 3 Feb 2023 20:43:12 +0100 Subject: [PATCH 522/814] hw/ppc/pegasos2: Fix a typo in a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Stefan Weil Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230203194312.33834745712@zero.eik.bme.hu> Signed-off-by: Daniel Henrique Barboza --- hw/ppc/pegasos2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 1a13632ba6..a9563f4fb2 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -564,7 +564,7 @@ static void dt_isa(PCIBus *bus, PCIDevice *d, FDTInfo *fi) qemu_fdt_setprop_string(fi->fdt, fi->path, "device_type", "isa"); qemu_fdt_setprop_string(fi->fdt, fi->path, "name", "isa"); - /* addional devices */ + /* additional devices */ g_string_printf(name, "%s/lpt@i3bc", fi->path); qemu_fdt_add_subnode(fi->fdt, name->str); qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); From 7be3fbbd9841acf7d9dba33cdedf73dd9052f666 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 21 Jan 2023 21:35:27 +0100 Subject: [PATCH 523/814] hw/display/sm501: Remove parenthesis around constant macro definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to wrap constants in parenthesis. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <9194546b73b05e7098761ec62b2dfd0699b97b65.1674333199.git.balaton@eik.bme.hu> Signed-off-by: Daniel Henrique Barboza --- hw/display/sm501.c | 386 ++++++++++++++++++++++----------------------- 1 file changed, 193 insertions(+), 193 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 52e42585af..0cbd1fecd5 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -50,10 +50,10 @@ /* System Configuration area */ /* System config base */ -#define SM501_SYS_CONFIG (0x000000) +#define SM501_SYS_CONFIG 0x000000 /* config 1 */ -#define SM501_SYSTEM_CONTROL (0x000000) +#define SM501_SYSTEM_CONTROL 0x000000 #define SM501_SYSCTRL_PANEL_TRISTATE (1 << 0) #define SM501_SYSCTRL_MEM_TRISTATE (1 << 1) @@ -72,13 +72,13 @@ /* miscellaneous control */ -#define SM501_MISC_CONTROL (0x000004) +#define SM501_MISC_CONTROL 0x000004 -#define SM501_MISC_BUS_SH (0x0) -#define SM501_MISC_BUS_PCI (0x1) -#define SM501_MISC_BUS_XSCALE (0x2) -#define SM501_MISC_BUS_NEC (0x6) -#define SM501_MISC_BUS_MASK (0x7) +#define SM501_MISC_BUS_SH 0x0 +#define SM501_MISC_BUS_PCI 0x1 +#define SM501_MISC_BUS_XSCALE 0x2 +#define SM501_MISC_BUS_NEC 0x6 +#define SM501_MISC_BUS_MASK 0x7 #define SM501_MISC_VR_62MB (1 << 3) #define SM501_MISC_CDR_RESET (1 << 7) @@ -103,22 +103,22 @@ -#define SM501_GPIO31_0_CONTROL (0x000008) -#define SM501_GPIO63_32_CONTROL (0x00000C) -#define SM501_DRAM_CONTROL (0x000010) +#define SM501_GPIO31_0_CONTROL 0x000008 +#define SM501_GPIO63_32_CONTROL 0x00000C +#define SM501_DRAM_CONTROL 0x000010 /* command list */ -#define SM501_ARBTRTN_CONTROL (0x000014) +#define SM501_ARBTRTN_CONTROL 0x000014 /* command list */ -#define SM501_COMMAND_LIST_STATUS (0x000024) +#define SM501_COMMAND_LIST_STATUS 0x000024 /* interrupt debug */ -#define SM501_RAW_IRQ_STATUS (0x000028) -#define SM501_RAW_IRQ_CLEAR (0x000028) -#define SM501_IRQ_STATUS (0x00002C) -#define SM501_IRQ_MASK (0x000030) -#define SM501_DEBUG_CONTROL (0x000034) +#define SM501_RAW_IRQ_STATUS 0x000028 +#define SM501_RAW_IRQ_CLEAR 0x000028 +#define SM501_IRQ_STATUS 0x00002C +#define SM501_IRQ_MASK 0x000030 +#define SM501_DEBUG_CONTROL 0x000034 /* power management */ #define SM501_POWERMODE_P2X_SRC (1 << 29) @@ -126,74 +126,74 @@ #define SM501_POWERMODE_M_SRC (1 << 12) #define SM501_POWERMODE_M1_SRC (1 << 4) -#define SM501_CURRENT_GATE (0x000038) -#define SM501_CURRENT_CLOCK (0x00003C) -#define SM501_POWER_MODE_0_GATE (0x000040) -#define SM501_POWER_MODE_0_CLOCK (0x000044) -#define SM501_POWER_MODE_1_GATE (0x000048) -#define SM501_POWER_MODE_1_CLOCK (0x00004C) -#define SM501_SLEEP_MODE_GATE (0x000050) -#define SM501_POWER_MODE_CONTROL (0x000054) +#define SM501_CURRENT_GATE 0x000038 +#define SM501_CURRENT_CLOCK 0x00003C +#define SM501_POWER_MODE_0_GATE 0x000040 +#define SM501_POWER_MODE_0_CLOCK 0x000044 +#define SM501_POWER_MODE_1_GATE 0x000048 +#define SM501_POWER_MODE_1_CLOCK 0x00004C +#define SM501_SLEEP_MODE_GATE 0x000050 +#define SM501_POWER_MODE_CONTROL 0x000054 /* power gates for units within the 501 */ -#define SM501_GATE_HOST (0) -#define SM501_GATE_MEMORY (1) -#define SM501_GATE_DISPLAY (2) -#define SM501_GATE_2D_ENGINE (3) -#define SM501_GATE_CSC (4) -#define SM501_GATE_ZVPORT (5) -#define SM501_GATE_GPIO (6) -#define SM501_GATE_UART0 (7) -#define SM501_GATE_UART1 (8) -#define SM501_GATE_SSP (10) -#define SM501_GATE_USB_HOST (11) -#define SM501_GATE_USB_GADGET (12) -#define SM501_GATE_UCONTROLLER (17) -#define SM501_GATE_AC97 (18) +#define SM501_GATE_HOST 0 +#define SM501_GATE_MEMORY 1 +#define SM501_GATE_DISPLAY 2 +#define SM501_GATE_2D_ENGINE 3 +#define SM501_GATE_CSC 4 +#define SM501_GATE_ZVPORT 5 +#define SM501_GATE_GPIO 6 +#define SM501_GATE_UART0 7 +#define SM501_GATE_UART1 8 +#define SM501_GATE_SSP 10 +#define SM501_GATE_USB_HOST 11 +#define SM501_GATE_USB_GADGET 12 +#define SM501_GATE_UCONTROLLER 17 +#define SM501_GATE_AC97 18 /* panel clock */ -#define SM501_CLOCK_P2XCLK (24) +#define SM501_CLOCK_P2XCLK 24 /* crt clock */ -#define SM501_CLOCK_V2XCLK (16) +#define SM501_CLOCK_V2XCLK 16 /* main clock */ -#define SM501_CLOCK_MCLK (8) +#define SM501_CLOCK_MCLK 8 /* SDRAM controller clock */ -#define SM501_CLOCK_M1XCLK (0) +#define SM501_CLOCK_M1XCLK 0 /* config 2 */ -#define SM501_PCI_MASTER_BASE (0x000058) -#define SM501_ENDIAN_CONTROL (0x00005C) -#define SM501_DEVICEID (0x000060) +#define SM501_PCI_MASTER_BASE 0x000058 +#define SM501_ENDIAN_CONTROL 0x00005C +#define SM501_DEVICEID 0x000060 /* 0x050100A0 */ -#define SM501_DEVICEID_SM501 (0x05010000) -#define SM501_DEVICEID_IDMASK (0xffff0000) -#define SM501_DEVICEID_REVMASK (0x000000ff) +#define SM501_DEVICEID_SM501 0x05010000 +#define SM501_DEVICEID_IDMASK 0xffff0000 +#define SM501_DEVICEID_REVMASK 0x000000ff -#define SM501_PLLCLOCK_COUNT (0x000064) -#define SM501_MISC_TIMING (0x000068) -#define SM501_CURRENT_SDRAM_CLOCK (0x00006C) +#define SM501_PLLCLOCK_COUNT 0x000064 +#define SM501_MISC_TIMING 0x000068 +#define SM501_CURRENT_SDRAM_CLOCK 0x00006C -#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074) +#define SM501_PROGRAMMABLE_PLL_CONTROL 0x000074 /* GPIO base */ -#define SM501_GPIO (0x010000) -#define SM501_GPIO_DATA_LOW (0x00) -#define SM501_GPIO_DATA_HIGH (0x04) -#define SM501_GPIO_DDR_LOW (0x08) -#define SM501_GPIO_DDR_HIGH (0x0C) -#define SM501_GPIO_IRQ_SETUP (0x10) -#define SM501_GPIO_IRQ_STATUS (0x14) -#define SM501_GPIO_IRQ_RESET (0x14) +#define SM501_GPIO 0x010000 +#define SM501_GPIO_DATA_LOW 0x00 +#define SM501_GPIO_DATA_HIGH 0x04 +#define SM501_GPIO_DDR_LOW 0x08 +#define SM501_GPIO_DDR_HIGH 0x0C +#define SM501_GPIO_IRQ_SETUP 0x10 +#define SM501_GPIO_IRQ_STATUS 0x14 +#define SM501_GPIO_IRQ_RESET 0x14 /* I2C controller base */ -#define SM501_I2C (0x010040) -#define SM501_I2C_BYTE_COUNT (0x00) -#define SM501_I2C_CONTROL (0x01) -#define SM501_I2C_STATUS (0x02) -#define SM501_I2C_RESET (0x02) -#define SM501_I2C_SLAVE_ADDRESS (0x03) -#define SM501_I2C_DATA (0x04) +#define SM501_I2C 0x010040 +#define SM501_I2C_BYTE_COUNT 0x00 +#define SM501_I2C_CONTROL 0x01 +#define SM501_I2C_STATUS 0x02 +#define SM501_I2C_RESET 0x02 +#define SM501_I2C_SLAVE_ADDRESS 0x03 +#define SM501_I2C_DATA 0x04 #define SM501_I2C_CONTROL_START (1 << 2) #define SM501_I2C_CONTROL_ENABLE (1 << 0) @@ -204,25 +204,25 @@ #define SM501_I2C_RESET_ERROR (1 << 2) /* SSP base */ -#define SM501_SSP (0x020000) +#define SM501_SSP 0x020000 /* Uart 0 base */ -#define SM501_UART0 (0x030000) +#define SM501_UART0 0x030000 /* Uart 1 base */ -#define SM501_UART1 (0x030020) +#define SM501_UART1 0x030020 /* USB host port base */ -#define SM501_USB_HOST (0x040000) +#define SM501_USB_HOST 0x040000 /* USB slave/gadget base */ -#define SM501_USB_GADGET (0x060000) +#define SM501_USB_GADGET 0x060000 /* USB slave/gadget data port base */ -#define SM501_USB_GADGET_DATA (0x070000) +#define SM501_USB_GADGET_DATA 0x070000 /* Display controller/video engine base */ -#define SM501_DC (0x080000) +#define SM501_DC 0x080000 /* common defines for the SM501 address registers */ #define SM501_ADDR_FLIP (1 << 31) @@ -237,12 +237,12 @@ #define SM501_FIFO_11 (0x3 << 16) /* common registers for panel and the crt */ -#define SM501_OFF_DC_H_TOT (0x000) -#define SM501_OFF_DC_V_TOT (0x008) -#define SM501_OFF_DC_H_SYNC (0x004) -#define SM501_OFF_DC_V_SYNC (0x00C) +#define SM501_OFF_DC_H_TOT 0x000 +#define SM501_OFF_DC_V_TOT 0x008 +#define SM501_OFF_DC_H_SYNC 0x004 +#define SM501_OFF_DC_V_SYNC 0x00C -#define SM501_DC_PANEL_CONTROL (0x000) +#define SM501_DC_PANEL_CONTROL 0x000 #define SM501_DC_PANEL_CONTROL_FPEN (1 << 27) #define SM501_DC_PANEL_CONTROL_BIAS (1 << 26) @@ -277,65 +277,65 @@ #define SM501_DC_PANEL_CONTROL_32BPP (2 << 0) -#define SM501_DC_PANEL_PANNING_CONTROL (0x004) -#define SM501_DC_PANEL_COLOR_KEY (0x008) -#define SM501_DC_PANEL_FB_ADDR (0x00C) -#define SM501_DC_PANEL_FB_OFFSET (0x010) -#define SM501_DC_PANEL_FB_WIDTH (0x014) -#define SM501_DC_PANEL_FB_HEIGHT (0x018) -#define SM501_DC_PANEL_TL_LOC (0x01C) -#define SM501_DC_PANEL_BR_LOC (0x020) -#define SM501_DC_PANEL_H_TOT (0x024) -#define SM501_DC_PANEL_H_SYNC (0x028) -#define SM501_DC_PANEL_V_TOT (0x02C) -#define SM501_DC_PANEL_V_SYNC (0x030) -#define SM501_DC_PANEL_CUR_LINE (0x034) +#define SM501_DC_PANEL_PANNING_CONTROL 0x004 +#define SM501_DC_PANEL_COLOR_KEY 0x008 +#define SM501_DC_PANEL_FB_ADDR 0x00C +#define SM501_DC_PANEL_FB_OFFSET 0x010 +#define SM501_DC_PANEL_FB_WIDTH 0x014 +#define SM501_DC_PANEL_FB_HEIGHT 0x018 +#define SM501_DC_PANEL_TL_LOC 0x01C +#define SM501_DC_PANEL_BR_LOC 0x020 +#define SM501_DC_PANEL_H_TOT 0x024 +#define SM501_DC_PANEL_H_SYNC 0x028 +#define SM501_DC_PANEL_V_TOT 0x02C +#define SM501_DC_PANEL_V_SYNC 0x030 +#define SM501_DC_PANEL_CUR_LINE 0x034 -#define SM501_DC_VIDEO_CONTROL (0x040) -#define SM501_DC_VIDEO_FB0_ADDR (0x044) -#define SM501_DC_VIDEO_FB_WIDTH (0x048) -#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C) -#define SM501_DC_VIDEO_TL_LOC (0x050) -#define SM501_DC_VIDEO_BR_LOC (0x054) -#define SM501_DC_VIDEO_SCALE (0x058) -#define SM501_DC_VIDEO_INIT_SCALE (0x05C) -#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060) -#define SM501_DC_VIDEO_FB1_ADDR (0x064) -#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068) +#define SM501_DC_VIDEO_CONTROL 0x040 +#define SM501_DC_VIDEO_FB0_ADDR 0x044 +#define SM501_DC_VIDEO_FB_WIDTH 0x048 +#define SM501_DC_VIDEO_FB0_LAST_ADDR 0x04C +#define SM501_DC_VIDEO_TL_LOC 0x050 +#define SM501_DC_VIDEO_BR_LOC 0x054 +#define SM501_DC_VIDEO_SCALE 0x058 +#define SM501_DC_VIDEO_INIT_SCALE 0x05C +#define SM501_DC_VIDEO_YUV_CONSTANTS 0x060 +#define SM501_DC_VIDEO_FB1_ADDR 0x064 +#define SM501_DC_VIDEO_FB1_LAST_ADDR 0x068 -#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080) -#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084) -#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088) -#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C) -#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090) -#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094) -#define SM501_DC_VIDEO_ALPHA_SCALE (0x098) -#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C) -#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0) -#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4) +#define SM501_DC_VIDEO_ALPHA_CONTROL 0x080 +#define SM501_DC_VIDEO_ALPHA_FB_ADDR 0x084 +#define SM501_DC_VIDEO_ALPHA_FB_OFFSET 0x088 +#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR 0x08C +#define SM501_DC_VIDEO_ALPHA_TL_LOC 0x090 +#define SM501_DC_VIDEO_ALPHA_BR_LOC 0x094 +#define SM501_DC_VIDEO_ALPHA_SCALE 0x098 +#define SM501_DC_VIDEO_ALPHA_INIT_SCALE 0x09C +#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY 0x0A0 +#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP 0x0A4 -#define SM501_DC_PANEL_HWC_BASE (0x0F0) -#define SM501_DC_PANEL_HWC_ADDR (0x0F0) -#define SM501_DC_PANEL_HWC_LOC (0x0F4) -#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8) -#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC) +#define SM501_DC_PANEL_HWC_BASE 0x0F0 +#define SM501_DC_PANEL_HWC_ADDR 0x0F0 +#define SM501_DC_PANEL_HWC_LOC 0x0F4 +#define SM501_DC_PANEL_HWC_COLOR_1_2 0x0F8 +#define SM501_DC_PANEL_HWC_COLOR_3 0x0FC #define SM501_HWC_EN (1 << 31) -#define SM501_OFF_HWC_ADDR (0x00) -#define SM501_OFF_HWC_LOC (0x04) -#define SM501_OFF_HWC_COLOR_1_2 (0x08) -#define SM501_OFF_HWC_COLOR_3 (0x0C) +#define SM501_OFF_HWC_ADDR 0x00 +#define SM501_OFF_HWC_LOC 0x04 +#define SM501_OFF_HWC_COLOR_1_2 0x08 +#define SM501_OFF_HWC_COLOR_3 0x0C -#define SM501_DC_ALPHA_CONTROL (0x100) -#define SM501_DC_ALPHA_FB_ADDR (0x104) -#define SM501_DC_ALPHA_FB_OFFSET (0x108) -#define SM501_DC_ALPHA_TL_LOC (0x10C) -#define SM501_DC_ALPHA_BR_LOC (0x110) -#define SM501_DC_ALPHA_CHROMA_KEY (0x114) -#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118) +#define SM501_DC_ALPHA_CONTROL 0x100 +#define SM501_DC_ALPHA_FB_ADDR 0x104 +#define SM501_DC_ALPHA_FB_OFFSET 0x108 +#define SM501_DC_ALPHA_TL_LOC 0x10C +#define SM501_DC_ALPHA_BR_LOC 0x110 +#define SM501_DC_ALPHA_CHROMA_KEY 0x114 +#define SM501_DC_ALPHA_COLOR_LOOKUP 0x118 -#define SM501_DC_CRT_CONTROL (0x200) +#define SM501_DC_CRT_CONTROL 0x200 #define SM501_DC_CRT_CONTROL_TVP (1 << 15) #define SM501_DC_CRT_CONTROL_CP (1 << 14) @@ -353,89 +353,89 @@ #define SM501_DC_CRT_CONTROL_16BPP (1 << 0) #define SM501_DC_CRT_CONTROL_32BPP (2 << 0) -#define SM501_DC_CRT_FB_ADDR (0x204) -#define SM501_DC_CRT_FB_OFFSET (0x208) -#define SM501_DC_CRT_H_TOT (0x20C) -#define SM501_DC_CRT_H_SYNC (0x210) -#define SM501_DC_CRT_V_TOT (0x214) -#define SM501_DC_CRT_V_SYNC (0x218) -#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C) -#define SM501_DC_CRT_CUR_LINE (0x220) -#define SM501_DC_CRT_MONITOR_DETECT (0x224) +#define SM501_DC_CRT_FB_ADDR 0x204 +#define SM501_DC_CRT_FB_OFFSET 0x208 +#define SM501_DC_CRT_H_TOT 0x20C +#define SM501_DC_CRT_H_SYNC 0x210 +#define SM501_DC_CRT_V_TOT 0x214 +#define SM501_DC_CRT_V_SYNC 0x218 +#define SM501_DC_CRT_SIGNATURE_ANALYZER 0x21C +#define SM501_DC_CRT_CUR_LINE 0x220 +#define SM501_DC_CRT_MONITOR_DETECT 0x224 -#define SM501_DC_CRT_HWC_BASE (0x230) -#define SM501_DC_CRT_HWC_ADDR (0x230) -#define SM501_DC_CRT_HWC_LOC (0x234) -#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238) -#define SM501_DC_CRT_HWC_COLOR_3 (0x23C) +#define SM501_DC_CRT_HWC_BASE 0x230 +#define SM501_DC_CRT_HWC_ADDR 0x230 +#define SM501_DC_CRT_HWC_LOC 0x234 +#define SM501_DC_CRT_HWC_COLOR_1_2 0x238 +#define SM501_DC_CRT_HWC_COLOR_3 0x23C -#define SM501_DC_PANEL_PALETTE (0x400) +#define SM501_DC_PANEL_PALETTE 0x400 -#define SM501_DC_VIDEO_PALETTE (0x800) +#define SM501_DC_VIDEO_PALETTE 0x800 -#define SM501_DC_CRT_PALETTE (0xC00) +#define SM501_DC_CRT_PALETTE 0xC00 /* Zoom Video port base */ -#define SM501_ZVPORT (0x090000) +#define SM501_ZVPORT 0x090000 /* AC97/I2S base */ -#define SM501_AC97 (0x0A0000) +#define SM501_AC97 0x0A0000 /* 8051 micro controller base */ -#define SM501_UCONTROLLER (0x0B0000) +#define SM501_UCONTROLLER 0x0B0000 /* 8051 micro controller SRAM base */ -#define SM501_UCONTROLLER_SRAM (0x0C0000) +#define SM501_UCONTROLLER_SRAM 0x0C0000 /* DMA base */ -#define SM501_DMA (0x0D0000) +#define SM501_DMA 0x0D0000 /* 2d engine base */ -#define SM501_2D_ENGINE (0x100000) -#define SM501_2D_SOURCE (0x00) -#define SM501_2D_DESTINATION (0x04) -#define SM501_2D_DIMENSION (0x08) -#define SM501_2D_CONTROL (0x0C) -#define SM501_2D_PITCH (0x10) -#define SM501_2D_FOREGROUND (0x14) -#define SM501_2D_BACKGROUND (0x18) -#define SM501_2D_STRETCH (0x1C) -#define SM501_2D_COLOR_COMPARE (0x20) -#define SM501_2D_COLOR_COMPARE_MASK (0x24) -#define SM501_2D_MASK (0x28) -#define SM501_2D_CLIP_TL (0x2C) -#define SM501_2D_CLIP_BR (0x30) -#define SM501_2D_MONO_PATTERN_LOW (0x34) -#define SM501_2D_MONO_PATTERN_HIGH (0x38) -#define SM501_2D_WINDOW_WIDTH (0x3C) -#define SM501_2D_SOURCE_BASE (0x40) -#define SM501_2D_DESTINATION_BASE (0x44) -#define SM501_2D_ALPHA (0x48) -#define SM501_2D_WRAP (0x4C) -#define SM501_2D_STATUS (0x50) +#define SM501_2D_ENGINE 0x100000 +#define SM501_2D_SOURCE 0x00 +#define SM501_2D_DESTINATION 0x04 +#define SM501_2D_DIMENSION 0x08 +#define SM501_2D_CONTROL 0x0C +#define SM501_2D_PITCH 0x10 +#define SM501_2D_FOREGROUND 0x14 +#define SM501_2D_BACKGROUND 0x18 +#define SM501_2D_STRETCH 0x1C +#define SM501_2D_COLOR_COMPARE 0x20 +#define SM501_2D_COLOR_COMPARE_MASK 0x24 +#define SM501_2D_MASK 0x28 +#define SM501_2D_CLIP_TL 0x2C +#define SM501_2D_CLIP_BR 0x30 +#define SM501_2D_MONO_PATTERN_LOW 0x34 +#define SM501_2D_MONO_PATTERN_HIGH 0x38 +#define SM501_2D_WINDOW_WIDTH 0x3C +#define SM501_2D_SOURCE_BASE 0x40 +#define SM501_2D_DESTINATION_BASE 0x44 +#define SM501_2D_ALPHA 0x48 +#define SM501_2D_WRAP 0x4C +#define SM501_2D_STATUS 0x50 -#define SM501_CSC_Y_SOURCE_BASE (0xC8) -#define SM501_CSC_CONSTANTS (0xCC) -#define SM501_CSC_Y_SOURCE_X (0xD0) -#define SM501_CSC_Y_SOURCE_Y (0xD4) -#define SM501_CSC_U_SOURCE_BASE (0xD8) -#define SM501_CSC_V_SOURCE_BASE (0xDC) -#define SM501_CSC_SOURCE_DIMENSION (0xE0) -#define SM501_CSC_SOURCE_PITCH (0xE4) -#define SM501_CSC_DESTINATION (0xE8) -#define SM501_CSC_DESTINATION_DIMENSION (0xEC) -#define SM501_CSC_DESTINATION_PITCH (0xF0) -#define SM501_CSC_SCALE_FACTOR (0xF4) -#define SM501_CSC_DESTINATION_BASE (0xF8) -#define SM501_CSC_CONTROL (0xFC) +#define SM501_CSC_Y_SOURCE_BASE 0xC8 +#define SM501_CSC_CONSTANTS 0xCC +#define SM501_CSC_Y_SOURCE_X 0xD0 +#define SM501_CSC_Y_SOURCE_Y 0xD4 +#define SM501_CSC_U_SOURCE_BASE 0xD8 +#define SM501_CSC_V_SOURCE_BASE 0xDC +#define SM501_CSC_SOURCE_DIMENSION 0xE0 +#define SM501_CSC_SOURCE_PITCH 0xE4 +#define SM501_CSC_DESTINATION 0xE8 +#define SM501_CSC_DESTINATION_DIMENSION 0xEC +#define SM501_CSC_DESTINATION_PITCH 0xF0 +#define SM501_CSC_SCALE_FACTOR 0xF4 +#define SM501_CSC_DESTINATION_BASE 0xF8 +#define SM501_CSC_CONTROL 0xFC /* 2d engine data port base */ -#define SM501_2D_ENGINE_DATA (0x110000) +#define SM501_2D_ENGINE_DATA 0x110000 /* end of register definitions */ -#define SM501_HWC_WIDTH (64) -#define SM501_HWC_HEIGHT (64) +#define SM501_HWC_WIDTH 64 +#define SM501_HWC_HEIGHT 64 /* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */ static const uint32_t sm501_mem_local_size[] = { From 57ad5b5ae04ce39f406795e657ca1c03e98e29cf Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 21 Jan 2023 21:35:28 +0100 Subject: [PATCH 524/814] hw/display/sm501: Remove unneeded casts from void pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is not needed in C. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <58f599387dd0739ea1880bfb678872c0be26bf1b.1674333199.git.balaton@eik.bme.hu> Signed-off-by: Daniel Henrique Barboza --- hw/display/sm501.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 0cbd1fecd5..1e17072452 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -868,7 +868,7 @@ static void sm501_2d_operation(SM501State *s) static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; uint32_t ret = 0; switch (addr) { @@ -928,7 +928,7 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, static void sm501_system_config_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_system_config_write((uint32_t)addr, (uint32_t)value); switch (addr) { @@ -996,7 +996,7 @@ static const MemoryRegionOps sm501_system_config_ops = { static uint64_t sm501_i2c_read(void *opaque, hwaddr addr, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; uint8_t ret = 0; switch (addr) { @@ -1023,7 +1023,7 @@ static uint64_t sm501_i2c_read(void *opaque, hwaddr addr, unsigned size) static void sm501_i2c_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_i2c_write((uint32_t)addr, (uint32_t)value); switch (addr) { @@ -1092,7 +1092,7 @@ static const MemoryRegionOps sm501_i2c_ops = { static uint32_t sm501_palette_read(void *opaque, hwaddr addr) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_palette_read((uint32_t)addr); @@ -1106,7 +1106,7 @@ static uint32_t sm501_palette_read(void *opaque, hwaddr addr) static void sm501_palette_write(void *opaque, hwaddr addr, uint32_t value) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_palette_write((uint32_t)addr, value); @@ -1121,7 +1121,7 @@ static void sm501_palette_write(void *opaque, hwaddr addr, static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; uint32_t ret = 0; switch (addr) { @@ -1234,7 +1234,7 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_disp_ctrl_write((uint32_t)addr, (uint32_t)value); switch (addr) { @@ -1379,7 +1379,7 @@ static const MemoryRegionOps sm501_disp_ctrl_ops = { static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; uint32_t ret = 0; switch (addr) { @@ -1457,7 +1457,7 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, static void sm501_2d_engine_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; trace_sm501_2d_engine_write((uint32_t)addr, (uint32_t)value); switch (addr) { @@ -1644,7 +1644,7 @@ static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width, static void sm501_update_display(void *opaque) { - SM501State *s = (SM501State *)opaque; + SM501State *s = opaque; DisplaySurface *surface = qemu_console_surface(s->con); DirtyBitmapSnapshot *snap; int y, c_x = 0, c_y = 0; From bd591dc1b3c39b7f73b8d9f20be6e9001c905238 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 21 Jan 2023 21:35:29 +0100 Subject: [PATCH 525/814] hw/display/sm501: Code style fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix checkpatch warning about multi-line comment. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <8801292992a304609e1eac680fe36b515592b926.1674333199.git.balaton@eik.bme.hu> Signed-off-by: Daniel Henrique Barboza --- hw/display/sm501.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 1e17072452..e1d0591d36 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1768,7 +1768,8 @@ static const GraphicHwOps sm501_ops = { static void sm501_reset(SM501State *s) { s->system_control = 0x00100000; /* 2D engine FIFO empty */ - /* Bits 17 (SH), 7 (CDR), 6:5 (Test), 2:0 (Bus) are all supposed + /* + * Bits 17 (SH), 7 (CDR), 6:5 (Test), 2:0 (Bus) are all supposed * to be determined at reset by GPIO lines which set config bits. * We hardwire them: * SH = 0 : Hitachi Ready Polarity == Active Low From 588c5b0b9fe7c27c61cd4bd57b21ebc0fd06b45f Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 4 Jan 2023 22:59:36 +0100 Subject: [PATCH 526/814] input/adb: Only include header where needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header hw/input/adb.h is included by some files that don't need it. Clean it up and include only where necessary. Signed-off-by: BALATON Zoltan Message-Id: Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/cuda.c | 2 -- hw/misc/macio/pmu.c | 3 --- hw/misc/mos6522.c | 1 - include/hw/misc/mac_via.h | 1 + include/hw/misc/macio/cuda.h | 1 + include/hw/misc/macio/pmu.h | 1 + include/hw/misc/mos6522.h | 3 +-- 7 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 853e88bfed..7208b90e12 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -27,8 +27,6 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "hw/input/adb.h" -#include "hw/misc/mos6522.h" #include "hw/misc/macio/cuda.h" #include "qapi/error.h" #include "qemu/timer.h" diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 97ef8c771b..8575bc1264 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -31,10 +31,7 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "hw/input/adb.h" #include "hw/irq.h" -#include "hw/misc/mos6522.h" -#include "hw/misc/macio/gpio.h" #include "hw/misc/macio/pmu.h" #include "qapi/error.h" #include "qemu/timer.h" diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index 0ed631186c..d6ba47bde9 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" -#include "hw/input/adb.h" #include "hw/irq.h" #include "hw/misc/mos6522.h" #include "hw/qdev-properties.h" diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index 5fe7a7f592..422da43bf9 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -12,6 +12,7 @@ #include "exec/memory.h" #include "hw/sysbus.h" #include "hw/misc/mos6522.h" +#include "hw/input/adb.h" #include "qom/object.h" diff --git a/include/hw/misc/macio/cuda.h b/include/hw/misc/macio/cuda.h index a71deec968..8a6678c749 100644 --- a/include/hw/misc/macio/cuda.h +++ b/include/hw/misc/macio/cuda.h @@ -26,6 +26,7 @@ #ifndef CUDA_H #define CUDA_H +#include "hw/input/adb.h" #include "hw/misc/mos6522.h" #include "qom/object.h" diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h index 00fcdd23f5..ba76afb52a 100644 --- a/include/hw/misc/macio/pmu.h +++ b/include/hw/misc/macio/pmu.h @@ -10,6 +10,7 @@ #ifndef PMU_H #define PMU_H +#include "hw/input/adb.h" #include "hw/misc/mos6522.h" #include "hw/misc/macio/gpio.h" #include "qom/object.h" diff --git a/include/hw/misc/mos6522.h b/include/hw/misc/mos6522.h index 05872fffc9..fba45668ab 100644 --- a/include/hw/misc/mos6522.h +++ b/include/hw/misc/mos6522.h @@ -27,9 +27,8 @@ #ifndef MOS6522_H #define MOS6522_H -#include "exec/memory.h" +#include "exec/hwaddr.h" #include "hw/sysbus.h" -#include "hw/input/adb.h" #include "qom/object.h" #define MOS6522_NUM_REGS 16 From 4db4847d83f11a33f08b75836d1116a1188121ca Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 4 Jan 2023 22:59:37 +0100 Subject: [PATCH 527/814] mac_{old,new}world: Use local variable instead of qdev_get_machine() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have machine in a local variable so no need to use qdev_get_machine(), also remove now unneeded line break. Signed-off-by: BALATON Zoltan Message-Id: <719299533b89aa4516966065eae05c75744f50d3.1672868854.git.balaton@eik.bme.hu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bernhard Beschow Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/ppc/mac_newworld.c | 3 +-- hw/ppc/mac_oldworld.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 601ea518f8..460c14b5e3 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -466,8 +466,7 @@ static void ppc_core99_init(MachineState *machine) fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); - object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg)); + object_property_add_child(OBJECT(machine), TYPE_FW_CFG, OBJECT(fw_cfg)); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 558c639202..5a7b25a4a8 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -303,8 +303,7 @@ static void ppc_heathrow_init(MachineState *machine) fw_cfg = FW_CFG(dev); qdev_prop_set_uint32(dev, "data_width", 1); qdev_prop_set_bit(dev, "dma_enabled", false); - object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG, - OBJECT(fw_cfg)); + object_property_add_child(OBJECT(machine), TYPE_FW_CFG, OBJECT(fw_cfg)); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, CFG_ADDR); From ea361fc348a43f5e751351191d8fc09fadd310bf Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 18 Jan 2023 01:32:32 +0100 Subject: [PATCH 528/814] hw/misc/macio: Avoid some QOM casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At several places we already have the object pointer with the right type so we don't need to cast it back and forth. Avoiding these casts improves readability. Signed-off-by: BALATON Zoltan Message-Id: <67b2d4700879c3b4cd574f1faa1a0d1950b3d0ee.1674001242.git.balaton@eik.bme.hu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/macio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 08dbdd7fc0..0dfe372965 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -220,11 +220,11 @@ static void macio_oldworld_init(Object *obj) DeviceState *dev; int i; - object_initialize_child(OBJECT(s), "pic", &os->pic, TYPE_HEATHROW); + object_initialize_child(obj, "pic", &os->pic, TYPE_HEATHROW); - object_initialize_child(OBJECT(s), "cuda", &s->cuda, TYPE_CUDA); + object_initialize_child(obj, "cuda", &s->cuda, TYPE_CUDA); - object_initialize_child(OBJECT(s), "nvram", &os->nvram, TYPE_MACIO_NVRAM); + object_initialize_child(obj, "nvram", &os->nvram, TYPE_MACIO_NVRAM); dev = DEVICE(&os->nvram); qdev_prop_set_uint32(dev, "size", MACIO_NVRAM_SIZE); qdev_prop_set_uint32(dev, "it_shift", 4); @@ -372,9 +372,9 @@ static void macio_newworld_init(Object *obj) NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); int i; - object_initialize_child(OBJECT(s), "pic", &ns->pic, TYPE_OPENPIC); + object_initialize_child(obj, "pic", &ns->pic, TYPE_OPENPIC); - object_initialize_child(OBJECT(s), "gpio", &ns->gpio, TYPE_MACIO_GPIO); + object_initialize_child(obj, "gpio", &ns->gpio, TYPE_MACIO_GPIO); for (i = 0; i < 2; i++) { macio_init_ide(s, &ns->ide[i], i); @@ -390,9 +390,9 @@ static void macio_instance_init(Object *obj) qbus_init(&s->macio_bus, sizeof(s->macio_bus), TYPE_MACIO_BUS, DEVICE(obj), "macio.0"); - object_initialize_child(OBJECT(s), "dbdma", &s->dbdma, TYPE_MAC_DBDMA); + object_initialize_child(obj, "dbdma", &s->dbdma, TYPE_MAC_DBDMA); - object_initialize_child(OBJECT(s), "escc", &s->escc, TYPE_ESCC); + object_initialize_child(obj, "escc", &s->escc, TYPE_ESCC); } static const VMStateDescription vmstate_macio_oldworld = { From 740ce28c464110d67e05cb1f99ade58329f74add Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 18 Jan 2023 01:32:33 +0100 Subject: [PATCH 529/814] hw/misc/macio: Rename sysbus_dev to sbd for consistency and brevity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functions use sysbus_dev while others sbd name for local variable storing a sysbus device pointer. Standardise on the shorter name to be consistent and make the code easier to read as short name is less distracting and needs less line breaks. Signed-off-by: BALATON Zoltan Message-Id: <6c79d6903fc11e153f8050a374904c2b5d5db585.1674001242.git.balaton@eik.bme.hu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/macio.c | 78 +++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 0dfe372965..4d7223cc85 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -96,14 +96,14 @@ static void macio_bar_setup(MacIOState *s) static void macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); - SysBusDevice *sysbus_dev; + SysBusDevice *sbd; if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&s->dbdma); + sbd = SYS_BUS_DEVICE(&s->dbdma); memory_region_add_subregion(&s->bar, 0x08000, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0); qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK); @@ -122,11 +122,10 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0, qemu_irq irq1, int dmaid, Error **errp) { - SysBusDevice *sysbus_dev; + SysBusDevice *sbd = SYS_BUS_DEVICE(ide); - sysbus_dev = SYS_BUS_DEVICE(ide); - sysbus_connect_irq(sysbus_dev, 0, irq0); - sysbus_connect_irq(sysbus_dev, 1, irq1); + sysbus_connect_irq(sbd, 0, irq0); + sysbus_connect_irq(sbd, 1, irq1); qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); object_property_set_link(OBJECT(ide), "dbdma", OBJECT(&s->dbdma), &error_abort); @@ -141,7 +140,7 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) OldWorldMacIOState *os = OLDWORLD_MACIO(d); DeviceState *pic_dev = DEVICE(&os->pic); Error *err = NULL; - SysBusDevice *sysbus_dev; + SysBusDevice *sbd; macio_common_realize(d, &err); if (err) { @@ -153,33 +152,30 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) if (!qdev_realize(DEVICE(&os->pic), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&os->pic); + sbd = SYS_BUS_DEVICE(&os->pic); memory_region_add_subregion(&s->bar, 0x0, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + sbd = SYS_BUS_DEVICE(&s->cuda); memory_region_add_subregion(&s->bar, 0x16000, - sysbus_mmio_get_region(sysbus_dev, 0)); - sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, - OLDWORLD_CUDA_IRQ)); + sysbus_mmio_get_region(sbd, 0)); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(pic_dev, OLDWORLD_CUDA_IRQ)); - sysbus_dev = SYS_BUS_DEVICE(&s->escc); - sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, - OLDWORLD_ESCCB_IRQ)); - sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, - OLDWORLD_ESCCA_IRQ)); + sbd = SYS_BUS_DEVICE(&s->escc); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(pic_dev, OLDWORLD_ESCCB_IRQ)); + sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(pic_dev, OLDWORLD_ESCCA_IRQ)); if (!qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&os->nvram); + sbd = SYS_BUS_DEVICE(&os->nvram); memory_region_add_subregion(&s->bar, 0x60000, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); pmac_format_nvram_partition(&os->nvram, os->nvram.size); /* IDE buses */ @@ -274,7 +270,7 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) NewWorldMacIOState *ns = NEWWORLD_MACIO(d); DeviceState *pic_dev = DEVICE(&ns->pic); Error *err = NULL; - SysBusDevice *sysbus_dev; + SysBusDevice *sbd; MemoryRegion *timer_memory = NULL; macio_common_realize(d, &err); @@ -285,16 +281,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) /* OpenPIC */ qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO); - sysbus_dev = SYS_BUS_DEVICE(&ns->pic); - sysbus_realize_and_unref(sysbus_dev, &error_fatal); + sbd = SYS_BUS_DEVICE(&ns->pic); + sysbus_realize_and_unref(sbd, &error_fatal); memory_region_add_subregion(&s->bar, 0x40000, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); - sysbus_dev = SYS_BUS_DEVICE(&s->escc); - sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, - NEWWORLD_ESCCB_IRQ)); - sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, - NEWWORLD_ESCCA_IRQ)); + sbd = SYS_BUS_DEVICE(&s->escc); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(pic_dev, NEWWORLD_ESCCB_IRQ)); + sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(pic_dev, NEWWORLD_ESCCA_IRQ)); /* IDE buses */ macio_realize_ide(s, &ns->ide[0], @@ -326,27 +320,26 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) if (!qdev_realize(DEVICE(&ns->gpio), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&ns->gpio); - sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, + sbd = SYS_BUS_DEVICE(&ns->gpio); + sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(pic_dev, NEWWORLD_EXTING_GPIO1)); - sysbus_connect_irq(sysbus_dev, 9, qdev_get_gpio_in(pic_dev, + sysbus_connect_irq(sbd, 9, qdev_get_gpio_in(pic_dev, NEWWORLD_EXTING_GPIO9)); memory_region_add_subregion(&s->bar, 0x50, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); /* PMU */ object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU); - object_property_set_link(OBJECT(&s->pmu), "gpio", OBJECT(sysbus_dev), + object_property_set_link(OBJECT(&s->pmu), "gpio", OBJECT(sbd), &error_abort); qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb); if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&s->pmu); - sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, - NEWWORLD_PMU_IRQ)); + sbd = SYS_BUS_DEVICE(&s->pmu); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(pic_dev, NEWWORLD_PMU_IRQ)); memory_region_add_subregion(&s->bar, 0x16000, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); } else { object_unparent(OBJECT(&ns->gpio)); @@ -358,11 +351,10 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) { return; } - sysbus_dev = SYS_BUS_DEVICE(&s->cuda); - sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, - NEWWORLD_CUDA_IRQ)); + sbd = SYS_BUS_DEVICE(&s->cuda); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(pic_dev, NEWWORLD_CUDA_IRQ)); memory_region_add_subregion(&s->bar, 0x16000, - sysbus_mmio_get_region(sysbus_dev, 0)); + sysbus_mmio_get_region(sbd, 0)); } } From af36fca459e8f3c8fadf887048a9d1bce1101f4e Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 18 Jan 2023 01:32:34 +0100 Subject: [PATCH 530/814] hw/misc/macio: Remove some single use local variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop some local variables that could just be substituted at the single place they were used. This makes the code shorter and simpler. Signed-off-by: BALATON Zoltan Message-Id: <165a4ea190af7c09832f50f02004fad82f704898.1674001242.git.balaton@eik.bme.hu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/macio.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 4d7223cc85..ae2a9a960d 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -53,10 +53,8 @@ */ static void macio_escc_legacy_setup(MacIOState *s) { - ESCCState *escc = ESCC(&s->escc); - SysBusDevice *sbd = SYS_BUS_DEVICE(escc); + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->escc); MemoryRegion *escc_legacy = g_new(MemoryRegion, 1); - MemoryRegion *bar = &s->bar; int i; static const int maps[] = { 0x00, 0x00, /* Command B */ @@ -80,16 +78,15 @@ static void macio_escc_legacy_setup(MacIOState *s) memory_region_add_subregion(escc_legacy, maps[i], port); } - memory_region_add_subregion(bar, 0x12000, escc_legacy); + memory_region_add_subregion(&s->bar, 0x12000, escc_legacy); } static void macio_bar_setup(MacIOState *s) { - ESCCState *escc = ESCC(&s->escc); - SysBusDevice *sbd = SYS_BUS_DEVICE(escc); - MemoryRegion *bar = &s->bar; + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->escc); + MemoryRegion *bar = sysbus_mmio_get_region(sbd, 0); - memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0)); + memory_region_add_subregion(&s->bar, 0x13000, bar); macio_escc_legacy_setup(s); } From 1d0c537985abf5c497498f985b746ebe3e0cca54 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 18 Jan 2023 01:32:35 +0100 Subject: [PATCH 531/814] hw/misc/macio: Return bool from functions taking errp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the convention to return bool from functions which take an error pointer which allows for callers to pass through their error pointer without needing a local. Signed-off-by: BALATON Zoltan Message-Id: Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/macio.c | 62 +++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index ae2a9a960d..265c0bbd8d 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -90,13 +90,13 @@ static void macio_bar_setup(MacIOState *s) macio_escc_legacy_setup(s); } -static void macio_common_realize(PCIDevice *d, Error **errp) +static bool macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); SysBusDevice *sbd; if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), errp)) { - return; + return false; } sbd = SYS_BUS_DEVICE(&s->dbdma); memory_region_add_subregion(&s->bar, 0x08000, @@ -108,14 +108,16 @@ static void macio_common_realize(PCIDevice *d, Error **errp) qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); if (!qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), errp)) { - return; + return false; } macio_bar_setup(s); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); + + return true; } -static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, +static bool macio_realize_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0, qemu_irq irq1, int dmaid, Error **errp) { @@ -128,7 +130,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, &error_abort); macio_ide_register_dma(ide); - qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp); + return qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp); } static void macio_oldworld_realize(PCIDevice *d, Error **errp) @@ -136,12 +138,9 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) MacIOState *s = MACIO(d); OldWorldMacIOState *os = OLDWORLD_MACIO(d); DeviceState *pic_dev = DEVICE(&os->pic); - Error *err = NULL; SysBusDevice *sbd; - macio_common_realize(d, &err); - if (err) { - error_propagate(errp, err); + if (!macio_common_realize(d, errp)) { return; } @@ -176,21 +175,17 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp) pmac_format_nvram_partition(&os->nvram, os->nvram.size); /* IDE buses */ - macio_realize_ide(s, &os->ide[0], - qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_IRQ), - qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_DMA_IRQ), - 0x16, &err); - if (err) { - error_propagate(errp, err); + if (!macio_realize_ide(s, &os->ide[0], + qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_IRQ), + qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_DMA_IRQ), + 0x16, errp)) { return; } - macio_realize_ide(s, &os->ide[1], - qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_IRQ), - qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_DMA_IRQ), - 0x1a, &err); - if (err) { - error_propagate(errp, err); + if (!macio_realize_ide(s, &os->ide[1], + qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_IRQ), + qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_DMA_IRQ), + 0x1a, errp)) { return; } } @@ -266,13 +261,10 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) MacIOState *s = MACIO(d); NewWorldMacIOState *ns = NEWWORLD_MACIO(d); DeviceState *pic_dev = DEVICE(&ns->pic); - Error *err = NULL; SysBusDevice *sbd; MemoryRegion *timer_memory = NULL; - macio_common_realize(d, &err); - if (err) { - error_propagate(errp, err); + if (!macio_common_realize(d, errp)) { return; } @@ -288,21 +280,17 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) sysbus_connect_irq(sbd, 1, qdev_get_gpio_in(pic_dev, NEWWORLD_ESCCA_IRQ)); /* IDE buses */ - macio_realize_ide(s, &ns->ide[0], - qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_IRQ), - qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_DMA_IRQ), - 0x16, &err); - if (err) { - error_propagate(errp, err); + if (!macio_realize_ide(s, &ns->ide[0], + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_IRQ), + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_DMA_IRQ), + 0x16, errp)) { return; } - macio_realize_ide(s, &ns->ide[1], - qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_IRQ), - qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_DMA_IRQ), - 0x1a, &err); - if (err) { - error_propagate(errp, err); + if (!macio_realize_ide(s, &ns->ide[1], + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_IRQ), + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_DMA_IRQ), + 0x1a, errp)) { return; } From 1f7888e2250adf3f4cffc24f7be29f062e095480 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 2 Feb 2023 01:24:05 +0100 Subject: [PATCH 532/814] mac_nvram: Add block backend to persist NVRAM contents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a way to set a backing store for the mac_nvram similar to what spapr_nvram or mac_via PRAM already does to allow to save its contents between runs. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <4b1605a9e484cc95f6e141f297487a070fd418ac.1675297286.git.balaton@eik.bme.hu> Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/nvram/mac_nvram.c | 28 ++++++++++++++++++++++++++++ include/hw/nvram/mac_nvram.h | 1 + 2 files changed, 29 insertions(+) diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 3d9ddda217..810e84f07e 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -24,9 +24,12 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/nvram/chrp_nvram.h" #include "hw/nvram/mac_nvram.h" #include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "sysemu/block-backend.h" #include "migration/vmstate.h" #include "qemu/cutils.h" #include "qemu/module.h" @@ -44,6 +47,9 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr, addr = (addr >> s->it_shift) & (s->size - 1); trace_macio_nvram_write(addr, value); s->data[addr] = value; + if (s->blk) { + blk_pwrite(s->blk, addr, 1, &s->data[addr], 0); + } } static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, @@ -91,6 +97,27 @@ static void macio_nvram_realizefn(DeviceState *dev, Error **errp) s->data = g_malloc0(s->size); + if (s->blk) { + int64_t len = blk_getlength(s->blk); + if (len < 0) { + error_setg_errno(errp, -len, + "could not get length of nvram backing image"); + return; + } else if (len != s->size) { + error_setg_errno(errp, -len, + "invalid size nvram backing image"); + return; + } + if (blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, errp) < 0) { + return; + } + if (blk_pread(s->blk, 0, s->size, s->data, 0) < 0) { + error_setg(errp, "can't read-nvram contents"); + return; + } + } + memory_region_init_io(&s->mem, OBJECT(s), &macio_nvram_ops, s, "macio-nvram", s->size << s->it_shift); sysbus_init_mmio(d, &s->mem); @@ -106,6 +133,7 @@ static void macio_nvram_unrealizefn(DeviceState *dev) static Property macio_nvram_properties[] = { DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0), DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0), + DEFINE_PROP_DRIVE("drive", MacIONVRAMState, blk), DEFINE_PROP_END_OF_LIST() }; diff --git a/include/hw/nvram/mac_nvram.h b/include/hw/nvram/mac_nvram.h index b780aca470..0c4dfaeff6 100644 --- a/include/hw/nvram/mac_nvram.h +++ b/include/hw/nvram/mac_nvram.h @@ -44,6 +44,7 @@ struct MacIONVRAMState { MemoryRegion mem; uint8_t *data; + BlockBackend *blk; }; void pmac_format_nvram_partition(MacIONVRAMState *nvr, int len); From 5df3eb4d361fd609632281969b101f4f84f1c4d8 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 2 Feb 2023 01:24:06 +0100 Subject: [PATCH 533/814] mac_oldworld: Allow specifying nvram backing store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a way to set a backing store for the mac_nvram. Use -drive file=nvram.img,format=raw,if=mtd to specify backing file where nvram.img must be MACIO_NVRAM_SIZE which is 8192 bytes. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1aadee8f0ca0f56cf1b7c45c3944676a07d91de9.1675297286.git.balaton@eik.bme.hu> Reviewed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland --- hw/ppc/mac_oldworld.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 5a7b25a4a8..2e4cc3fe0b 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -102,7 +102,7 @@ static void ppc_heathrow_init(MachineState *machine) DeviceState *dev, *pic_dev, *grackle_dev; BusState *adb_bus; uint16_t ppc_boot_device; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + DriveInfo *dinfo, *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; uint64_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TBFREQ; @@ -245,6 +245,12 @@ static void ppc_heathrow_init(MachineState *machine) qdev_prop_set_chr(dev, "chrA", serial_hd(0)); qdev_prop_set_chr(dev, "chrB", serial_hd(1)); + dinfo = drive_get(IF_MTD, 0, 0); + if (dinfo) { + dev = DEVICE(object_resolve_path_component(macio, "nvram")); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); + } + pci_realize_and_unref(PCI_DEVICE(macio), pci_bus, &error_fatal); pic_dev = DEVICE(object_resolve_path_component(macio, "pic")); From 9b97d0774826eccf8dea9c27e4cebc68129ac4eb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Jan 2023 15:02:07 +0100 Subject: [PATCH 534/814] scripts/ci: remove unnecessary checks from CentOS playbook Since this playbook is meant for a CentOS 8 install, no need to check the facts. Signed-off-by: Paolo Bonzini --- scripts/ci/org.centos/stream/8/build-environment.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/ci/org.centos/stream/8/build-environment.yml b/scripts/ci/org.centos/stream/8/build-environment.yml index 42b0471634..fe8807b7b0 100644 --- a/scripts/ci/org.centos/stream/8/build-environment.yml +++ b/scripts/ci/org.centos/stream/8/build-environment.yml @@ -17,8 +17,6 @@ option: enabled value: "1" when: - - ansible_facts['distribution'] == 'CentOS' - - ansible_facts['distribution_major_version'] == '8' - centos_stream_8 - name: Install basic packages to build QEMU on CentOS Stream 8 @@ -46,6 +44,4 @@ - systemd-devel state: present when: - - ansible_facts['distribution'] == 'CentOS' - - ansible_facts['distribution_major_version'] == '8' - centos_stream_8 From 4b950af8d3c4f4e7e6a76396062d5760e70a743e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Jan 2023 14:23:09 +0100 Subject: [PATCH 535/814] scripts/ci: support CentOS Stream 8 in build-environment.yaml Update the CI playbook so that it is able to prepare a system with a fresh CentOS Stream 8 install, rather than just support RHEL. Signed-off-by: Paolo Bonzini --- scripts/ci/setup/build-environment.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 58438008ee..c3cebc42ac 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -130,6 +130,16 @@ - ansible_facts['distribution_version'] == '20.04' - ansible_facts['architecture'] == 'aarch64' + - name: Enable PowerTools repo on CentOS 8 + ini_file: + path: /etc/yum.repos.d/CentOS-Stream-PowerTools.repo + section: powertools + option: enabled + value: "1" + when: + - ansible_facts['distribution_file_variety'] == 'CentOS' + - ansible_facts['distribution_major_version'] == '8' + - name: Install basic packages to build QEMU on EL8 dnf: # This list of packages start with tests/docker/dockerfiles/centos8.docker @@ -164,7 +174,7 @@ - zlib-devel state: present when: - - ansible_facts['distribution_file_variety'] == 'RedHat' + - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] - ansible_facts['distribution_version'] == '8' - name: Install packages only available on x86 and aarch64 @@ -174,6 +184,6 @@ - spice-server state: present when: - - ansible_facts['distribution_file_variety'] == 'RedHat' + - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] - ansible_facts['distribution_version'] == '8' - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64' From a925323008563236ae7954bed97b6c4d64c38f90 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Jan 2023 15:02:30 +0100 Subject: [PATCH 536/814] scripts/ci: add capstone development packages Signed-off-by: Paolo Bonzini --- scripts/ci/org.centos/stream/8/build-environment.yml | 9 +++++++++ scripts/ci/setup/build-environment.yml | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/scripts/ci/org.centos/stream/8/build-environment.yml b/scripts/ci/org.centos/stream/8/build-environment.yml index fe8807b7b0..95474ad034 100644 --- a/scripts/ci/org.centos/stream/8/build-environment.yml +++ b/scripts/ci/org.centos/stream/8/build-environment.yml @@ -10,6 +10,14 @@ check_mode: yes register: centos_stream_8 + - name: Enable EPEL repo on CentOS Stream 8 + dnf: + name: + - epel-release + state: present + when: + - centos_stream_8 + - name: Enable PowerTools repo on CentOS Stream 8 ini_file: path: /etc/yum.repos.d/CentOS-Stream-PowerTools.repo @@ -22,6 +30,7 @@ - name: Install basic packages to build QEMU on CentOS Stream 8 dnf: name: + - capstone-devel - device-mapper-multipath-devel - glusterfs-api-devel - gnutls-devel diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index c3cebc42ac..8d76404c6c 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -46,6 +46,7 @@ - libbrlapi-dev - libbz2-dev - libcacard-dev + - libcapstone-dev - libcap-ng-dev - libcurl4-gnutls-dev - libdrm-dev @@ -130,6 +131,15 @@ - ansible_facts['distribution_version'] == '20.04' - ansible_facts['architecture'] == 'aarch64' + - name: Enable EPEL repo on EL8 + dnf: + name: + - epel-release + state: present + when: + - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] + - ansible_facts['distribution_major_version'] == '8' + - name: Enable PowerTools repo on CentOS 8 ini_file: path: /etc/yum.repos.d/CentOS-Stream-PowerTools.repo @@ -148,6 +158,7 @@ name: - bzip2 - bzip2-devel + - capstone-devel - dbus-daemon - diffutils - gcc From cb1513df3fe4ee99eda8b0f69e044655f5979171 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Jan 2023 14:31:24 +0100 Subject: [PATCH 537/814] scripts/ci: unify package lists for CentOS in build-environment files scripts/ci/org.centos/stream/8/build-environment.yml has a slightly different list of packages compared to scripts/ci/setup/build-environment.yaml. Make them the same. Signed-off-by: Paolo Bonzini --- .../org.centos/stream/8/build-environment.yml | 25 +++++++++++++++++++ scripts/ci/setup/build-environment.yml | 19 ++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/scripts/ci/org.centos/stream/8/build-environment.yml b/scripts/ci/org.centos/stream/8/build-environment.yml index 95474ad034..b1768d18af 100644 --- a/scripts/ci/org.centos/stream/8/build-environment.yml +++ b/scripts/ci/org.centos/stream/8/build-environment.yml @@ -30,13 +30,26 @@ - name: Install basic packages to build QEMU on CentOS Stream 8 dnf: name: + - bzip2 + - bzip2-devel - capstone-devel + - dbus-daemon - device-mapper-multipath-devel + - diffutils + - gcc + - gcc-c++ + - genisoimage + - gettext + - git + - glib2-devel - glusterfs-api-devel - gnutls-devel + - libaio-devel - libcap-ng-devel - libcurl-devel + - libepoxy-devel - libfdt-devel + - libgcrypt-devel - libiscsi-devel - libpmem-devel - librados-devel @@ -44,13 +57,25 @@ - libseccomp-devel - libssh-devel - libxkbcommon-devel + - lzo-devel + - make + - mesa-libEGL-devel + - nettle-devel - ninja-build + - nmap-ncat - numactl-devel + - pixman-devel + - python36 - python3-sphinx + - rdma-core-devel - redhat-rpm-config - snappy-devel + - spice-glib-devel - spice-server-devel - systemd-devel + - systemtap-sdt-devel + - tar + - zlib-devel state: present when: - centos_stream_8 diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 8d76404c6c..2274f736f7 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -160,6 +160,7 @@ - bzip2-devel - capstone-devel - dbus-daemon + - device-mapper-multipath-devel - diffutils - gcc - gcc-c++ @@ -167,19 +168,36 @@ - gettext - git - glib2-devel + - glusterfs-api-devel + - gnutls-devel - libaio-devel + - libcap-ng-devel + - libcurl-devel - libepoxy-devel + - libfdt-devel - libgcrypt-devel + - libiscsi-devel + - libpmem-devel + - librados-devel + - librbd-devel + - libseccomp-devel + - libssh-devel + - libxkbcommon-devel - lzo-devel - make - mesa-libEGL-devel - nettle-devel - ninja-build - nmap-ncat + - numactl-devel - pixman-devel - python36 + - python3-sphinx - rdma-core-devel + - redhat-rpm-config + - snappy-devel - spice-glib-devel + - systemd-devel - systemtap-sdt-devel - tar - zlib-devel @@ -193,6 +211,7 @@ # Spice server not available in ppc64le name: - spice-server + - spice-server-devel state: present when: - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] From 11b4a4eeec6054161aafdcb2f2faeb7c6ff36c99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Jan 2023 14:35:26 +0100 Subject: [PATCH 538/814] scripts/ci: bump CentOS Python to 3.8 Signed-off-by: Paolo Bonzini --- .../ci/org.centos/stream/8/build-environment.yml | 2 +- scripts/ci/org.centos/stream/8/x86_64/configure | 1 + scripts/ci/setup/build-environment.yml | 14 +++++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/ci/org.centos/stream/8/build-environment.yml b/scripts/ci/org.centos/stream/8/build-environment.yml index b1768d18af..0d094d70c3 100644 --- a/scripts/ci/org.centos/stream/8/build-environment.yml +++ b/scripts/ci/org.centos/stream/8/build-environment.yml @@ -65,7 +65,7 @@ - nmap-ncat - numactl-devel - pixman-devel - - python36 + - python38 - python3-sphinx - rdma-core-devel - redhat-rpm-config diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure index 75882faa9c..65eacf3c56 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/configure +++ b/scripts/ci/org.centos/stream/8/x86_64/configure @@ -16,6 +16,7 @@ # that patches adding downstream specific devices are not available. # ../configure \ +--python=/usr/bin/python3.8 \ --prefix="/usr" \ --libdir="/usr/lib64" \ --datadir="/usr/share" \ diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index 2274f736f7..78b1021cd4 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -191,7 +191,7 @@ - nmap-ncat - numactl-devel - pixman-devel - - python36 + - python38 - python3-sphinx - rdma-core-devel - redhat-rpm-config @@ -217,3 +217,15 @@ - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] - ansible_facts['distribution_version'] == '8' - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64' + + - name: Check whether the Python runtime version is managed by alternatives + stat: + path: /etc/alternatives/python3 + register: python3 + + - name: Set default Python runtime to 3.8 on EL8 + command: alternatives --set python3 /usr/bin/python3.8 + when: + - ansible_facts['distribution_file_variety'] in ['RedHat', 'CentOS'] + - ansible_facts['distribution_version'] == '8' + - python3.stat.islnk and python3.stat.lnk_target != '/usr/bin/python3.8' From 301d7ffe5f630dc5d0e2a3638b9eae7a00b1088a Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 20 Jan 2023 11:31:47 -0500 Subject: [PATCH 539/814] migration: Fix migration crash when target psize larger than host Commit d9e474ea56 overlooked the case where the target psize is even larger than the host psize. One example is Alpha has 8K page size and migration will start to crash the source QEMU when running Alpha migration on x86. Fix it by detecting that case and set host start/end just to cover the single page to be migrated. This will slightly optimize the common case where host psize equals to guest psize so we don't even need to do the roundups, but that's trivial. Cc: qemu-stable@nongnu.org Reported-by: Thomas Huth Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1456 Fixes: d9e474ea56 ("migration: Teach PSS about host page") Signed-off-by: Peter Xu Reviewed-by: Thomas Huth Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/ram.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 334309f1c6..68a45338e3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2319,8 +2319,25 @@ static void pss_host_page_prepare(PageSearchStatus *pss) size_t guest_pfns = qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; pss->host_page_sending = true; - pss->host_page_start = ROUND_DOWN(pss->page, guest_pfns); - pss->host_page_end = ROUND_UP(pss->page + 1, guest_pfns); + if (guest_pfns <= 1) { + /* + * This covers both when guest psize == host psize, or when guest + * has larger psize than the host (guest_pfns==0). + * + * For the latter, we always send one whole guest page per + * iteration of the host page (example: an Alpha VM on x86 host + * will have guest psize 8K while host psize 4K). + */ + pss->host_page_start = pss->page; + pss->host_page_end = pss->page + 1; + } else { + /* + * The host page spans over multiple guest pages, we send them + * within the same host page iteration. + */ + pss->host_page_start = ROUND_DOWN(pss->page, guest_pfns); + pss->host_page_end = ROUND_UP(pss->page + 1, guest_pfns); + } } /* From 255dc7af7e65588d36319129718ddfdfeabac898 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Sun, 2 Oct 2022 23:17:49 +0200 Subject: [PATCH 540/814] migration: No save_live_pending() method uses the QEMUFile parameter So remove it everywhere. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- hw/s390x/s390-stattrib.c | 2 +- hw/vfio/migration.c | 2 +- include/migration/register.h | 2 +- migration/block-dirty-bitmap.c | 2 +- migration/block.c | 2 +- migration/migration.c | 2 +- migration/ram.c | 2 +- migration/savevm.c | 4 ++-- migration/savevm.h | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 9eda1c3b2a..a553a1e850 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -182,7 +182,7 @@ static int cmma_save_setup(QEMUFile *f, void *opaque) return 0; } -static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, +static void cmma_save_pending(void *opaque, uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index c74453e0b5..b2125c7607 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -456,7 +456,7 @@ static void vfio_save_cleanup(void *opaque) trace_vfio_save_cleanup(vbasedev->name); } -static void vfio_save_pending(QEMUFile *f, void *opaque, +static void vfio_save_pending(void *opaque, uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, diff --git a/include/migration/register.h b/include/migration/register.h index c1dcff0f90..6ca71367af 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -46,7 +46,7 @@ typedef struct SaveVMHandlers { /* This runs outside the iothread lock! */ int (*save_setup)(QEMUFile *f, void *opaque); - void (*save_live_pending)(QEMUFile *f, void *opaque, + void (*save_live_pending)(void *opaque, uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 15127d489a..c27ef9b033 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -762,7 +762,7 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) return 0; } -static void dirty_bitmap_save_pending(QEMUFile *f, void *opaque, +static void dirty_bitmap_save_pending(void *opaque, uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, diff --git a/migration/block.c b/migration/block.c index 5da15a62de..47852b8d58 100644 --- a/migration/block.c +++ b/migration/block.c @@ -863,7 +863,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) return 0; } -static void block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, +static void block_save_pending(void *opaque, uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/migration/migration.c b/migration/migration.c index 56859d5869..5e2c891845 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3781,7 +3781,7 @@ static MigIterateState migration_iteration_run(MigrationState *s) uint64_t pending_size, pend_pre, pend_compat, pend_post; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; - qemu_savevm_state_pending(s->to_dst_file, s->threshold_size, &pend_pre, + qemu_savevm_state_pending(s->threshold_size, &pend_pre, &pend_compat, &pend_post); pending_size = pend_pre + pend_compat + pend_post; diff --git a/migration/ram.c b/migration/ram.c index 68a45338e3..389739f162 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3409,7 +3409,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) return 0; } -static void ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, +static void ram_save_pending(void *opaque, uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/migration/savevm.c b/migration/savevm.c index a783789430..5e4bccb966 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1472,7 +1472,7 @@ flush: * the result is split into the amount for units that can and * for units that can't do postcopy. */ -void qemu_savevm_state_pending(QEMUFile *f, uint64_t threshold_size, +void qemu_savevm_state_pending(uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) @@ -1493,7 +1493,7 @@ void qemu_savevm_state_pending(QEMUFile *f, uint64_t threshold_size, continue; } } - se->ops->save_live_pending(f, se->opaque, threshold_size, + se->ops->save_live_pending(se->opaque, threshold_size, res_precopy_only, res_compatible, res_postcopy_only); } diff --git a/migration/savevm.h b/migration/savevm.h index 6461342cb4..524cf12f25 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -40,7 +40,7 @@ void qemu_savevm_state_cleanup(void); void qemu_savevm_state_complete_postcopy(QEMUFile *f); int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, bool inactivate_disks); -void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size, +void qemu_savevm_state_pending(uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only); From c8df4a7aeffcb46020f610526eea621fa5b0cd47 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 3 Oct 2022 02:00:03 +0200 Subject: [PATCH 541/814] migration: Split save_live_pending() into state_pending_* We split the function into to: - state_pending_estimate: We estimate the remaining state size without stopping the machine. - state pending_exact: We calculate the exact amount of remaining state. The only "device" that implements different functions for _estimate() and _exact() is ram. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- docs/devel/migration.rst | 18 ++++++++------- docs/devel/vfio-migration.rst | 4 ++-- hw/s390x/s390-stattrib.c | 11 +++++---- hw/vfio/migration.c | 21 +++++++++-------- hw/vfio/trace-events | 2 +- include/migration/register.h | 19 +++++++++------ migration/block-dirty-bitmap.c | 15 ++++++------ migration/block.c | 13 ++++++----- migration/migration.c | 20 +++++++++++----- migration/ram.c | 35 ++++++++++++++++++++-------- migration/savevm.c | 42 +++++++++++++++++++++++++++------- migration/savevm.h | 12 ++++++---- migration/trace-events | 7 +++--- 13 files changed, 143 insertions(+), 76 deletions(-) diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst index 3e9656d8e0..6f65c23b47 100644 --- a/docs/devel/migration.rst +++ b/docs/devel/migration.rst @@ -482,15 +482,17 @@ An iterative device must provide: - A ``load_setup`` function that initialises the data structures on the destination. - - A ``save_live_pending`` function that is called repeatedly and must - indicate how much more data the iterative data must save. The core - migration code will use this to determine when to pause the CPUs - and complete the migration. + - A ``state_pending_exact`` function that indicates how much more + data we must save. The core migration code will use this to + determine when to pause the CPUs and complete the migration. - - A ``save_live_iterate`` function (called after ``save_live_pending`` - when there is significant data still to be sent). It should send - a chunk of data until the point that stream bandwidth limits tell it - to stop. Each call generates one section. + - A ``state_pending_estimate`` function that indicates how much more + data we must save. When the estimated amount is smaller than the + threshold, we call ``state_pending_exact``. + + - A ``save_live_iterate`` function should send a chunk of data until + the point that stream bandwidth limits tell it to stop. Each call + generates one section. - A ``save_live_complete_precopy`` function that must transmit the last section for the device containing any remaining data. diff --git a/docs/devel/vfio-migration.rst b/docs/devel/vfio-migration.rst index 9ff6163c88..673057c90d 100644 --- a/docs/devel/vfio-migration.rst +++ b/docs/devel/vfio-migration.rst @@ -28,7 +28,7 @@ VFIO implements the device hooks for the iterative approach as follows: * A ``load_setup`` function that sets up the migration region on the destination and sets _RESUMING flag in the VFIO device state. -* A ``save_live_pending`` function that reads pending_bytes from the vendor +* A ``state_pending_exact`` function that reads pending_bytes from the vendor driver, which indicates the amount of data that the vendor driver has yet to save for the VFIO device. @@ -114,7 +114,7 @@ Live migration save path (RUNNING, _SETUP, _RUNNING|_SAVING) | (RUNNING, _ACTIVE, _RUNNING|_SAVING) - If device is active, get pending_bytes by .save_live_pending() + If device is active, get pending_bytes by .state_pending_exact() If total pending_bytes >= threshold_size, call .save_live_iterate() Data of VFIO device for pre-copy phase is copied Iterate till total pending bytes converge and are less than threshold diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index a553a1e850..8f573ebb10 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -182,10 +182,10 @@ static int cmma_save_setup(QEMUFile *f, void *opaque) return 0; } -static void cmma_save_pending(void *opaque, uint64_t max_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +static void cmma_state_pending(void *opaque, uint64_t max_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { S390StAttribState *sas = S390_STATTRIB(opaque); S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); @@ -371,7 +371,8 @@ static SaveVMHandlers savevm_s390_stattrib_handlers = { .save_setup = cmma_save_setup, .save_live_iterate = cmma_save_iterate, .save_live_complete_precopy = cmma_save_complete, - .save_live_pending = cmma_save_pending, + .state_pending_exact = cmma_state_pending, + .state_pending_estimate = cmma_state_pending, .save_cleanup = cmma_save_cleanup, .load_state = cmma_load, .is_active = cmma_active, diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index b2125c7607..c49ca466d4 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -456,11 +456,11 @@ static void vfio_save_cleanup(void *opaque) trace_vfio_save_cleanup(vbasedev->name); } -static void vfio_save_pending(void *opaque, - uint64_t threshold_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +static void vfio_state_pending(void *opaque, + uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; @@ -473,7 +473,7 @@ static void vfio_save_pending(void *opaque, *res_precopy_only += migration->pending_bytes; - trace_vfio_save_pending(vbasedev->name, *res_precopy_only, + trace_vfio_state_pending(vbasedev->name, *res_precopy_only, *res_postcopy_only, *res_compatible); } @@ -515,9 +515,9 @@ static int vfio_save_iterate(QEMUFile *f, void *opaque) } /* - * Reset pending_bytes as .save_live_pending is not called during savevm or - * snapshot case, in such case vfio_update_pending() at the start of this - * function updates pending_bytes. + * Reset pending_bytes as state_pending* are not called during + * savevm or snapshot case, in such case vfio_update_pending() at + * the start of this function updates pending_bytes. */ migration->pending_bytes = 0; trace_vfio_save_iterate(vbasedev->name, data_size); @@ -685,7 +685,8 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) static SaveVMHandlers savevm_vfio_handlers = { .save_setup = vfio_save_setup, .save_cleanup = vfio_save_cleanup, - .save_live_pending = vfio_save_pending, + .state_pending_exact = vfio_state_pending, + .state_pending_estimate = vfio_state_pending, .save_live_iterate = vfio_save_iterate, .save_live_complete_precopy = vfio_save_complete_precopy, .save_state = vfio_save_state, diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 73dffe9e00..52de1c84f8 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -157,7 +157,7 @@ vfio_save_cleanup(const char *name) " (%s)" vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 vfio_save_device_config_state(const char *name) " (%s)" -vfio_save_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 +vfio_state_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" vfio_save_complete_precopy(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" diff --git a/include/migration/register.h b/include/migration/register.h index 6ca71367af..15cf32994d 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -46,11 +46,6 @@ typedef struct SaveVMHandlers { /* This runs outside the iothread lock! */ int (*save_setup)(QEMUFile *f, void *opaque); - void (*save_live_pending)(void *opaque, - uint64_t threshold_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only); /* Note for save_live_pending: * - res_precopy_only is for data which must be migrated in precopy phase * or in stopped state, in other words - before target vm start @@ -61,8 +56,18 @@ typedef struct SaveVMHandlers { * Sum of res_postcopy_only, res_compatible and res_postcopy_only is the * whole amount of pending data. */ - - + /* This estimates the remaining data to transfer */ + void (*state_pending_estimate)(void *opaque, + uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only); + /* This calculate the exact remaining data to transfer */ + void (*state_pending_exact)(void *opaque, + uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only); LoadStateHandler *load_state; int (*load_setup)(QEMUFile *f, void *opaque); int (*load_cleanup)(void *opaque); diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index c27ef9b033..6fac9fb34f 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -762,11 +762,11 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) return 0; } -static void dirty_bitmap_save_pending(void *opaque, - uint64_t max_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +static void dirty_bitmap_state_pending(void *opaque, + uint64_t max_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms; @@ -784,7 +784,7 @@ static void dirty_bitmap_save_pending(void *opaque, qemu_mutex_unlock_iothread(); - trace_dirty_bitmap_save_pending(pending, max_size); + trace_dirty_bitmap_state_pending(pending); *res_postcopy_only += pending; } @@ -1253,7 +1253,8 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = { .save_live_complete_postcopy = dirty_bitmap_save_complete, .save_live_complete_precopy = dirty_bitmap_save_complete, .has_postcopy = dirty_bitmap_has_postcopy, - .save_live_pending = dirty_bitmap_save_pending, + .state_pending_exact = dirty_bitmap_state_pending, + .state_pending_estimate = dirty_bitmap_state_pending, .save_live_iterate = dirty_bitmap_save_iterate, .is_active_iterate = dirty_bitmap_is_active_iterate, .load_state = dirty_bitmap_load, diff --git a/migration/block.c b/migration/block.c index 47852b8d58..544e74e9c5 100644 --- a/migration/block.c +++ b/migration/block.c @@ -863,10 +863,10 @@ static int block_save_complete(QEMUFile *f, void *opaque) return 0; } -static void block_save_pending(void *opaque, uint64_t max_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +static void block_state_pending(void *opaque, uint64_t max_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { /* Estimate pending number of bytes to send */ uint64_t pending; @@ -885,7 +885,7 @@ static void block_save_pending(void *opaque, uint64_t max_size, pending = BLK_MIG_BLOCK_SIZE; } - trace_migration_block_save_pending(pending); + trace_migration_block_state_pending(pending); /* We don't do postcopy */ *res_precopy_only += pending; } @@ -1020,7 +1020,8 @@ static SaveVMHandlers savevm_block_handlers = { .save_setup = block_save_setup, .save_live_iterate = block_save_iterate, .save_live_complete_precopy = block_save_complete, - .save_live_pending = block_save_pending, + .state_pending_exact = block_state_pending, + .state_pending_estimate = block_state_pending, .load_state = block_load, .save_cleanup = block_migration_cleanup, .is_active = block_is_active, diff --git a/migration/migration.c b/migration/migration.c index 5e2c891845..877a6f7011 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3778,15 +3778,23 @@ typedef enum { */ static MigIterateState migration_iteration_run(MigrationState *s) { - uint64_t pending_size, pend_pre, pend_compat, pend_post; + uint64_t pend_pre, pend_compat, pend_post; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; - qemu_savevm_state_pending(s->threshold_size, &pend_pre, - &pend_compat, &pend_post); - pending_size = pend_pre + pend_compat + pend_post; + qemu_savevm_state_pending_estimate(s->threshold_size, &pend_pre, + &pend_compat, &pend_post); + uint64_t pending_size = pend_pre + pend_compat + pend_post; - trace_migrate_pending(pending_size, s->threshold_size, - pend_pre, pend_compat, pend_post); + trace_migrate_pending_estimate(pending_size, s->threshold_size, + pend_pre, pend_compat, pend_post); + + if (pend_pre + pend_compat <= s->threshold_size) { + qemu_savevm_state_pending_exact(s->threshold_size, &pend_pre, + &pend_compat, &pend_post); + pending_size = pend_pre + pend_compat + pend_post; + trace_migrate_pending_exact(pending_size, s->threshold_size, + pend_pre, pend_compat, pend_post); + } if (pending_size && pending_size >= s->threshold_size) { /* Still a significant amount to transfer */ diff --git a/migration/ram.c b/migration/ram.c index 389739f162..56ff9cd29d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3409,19 +3409,35 @@ static int ram_save_complete(QEMUFile *f, void *opaque) return 0; } -static void ram_save_pending(void *opaque, uint64_t max_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +static void ram_state_pending_estimate(void *opaque, uint64_t max_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { RAMState **temp = opaque; RAMState *rs = *temp; - uint64_t remaining_size; - remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE; + uint64_t remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE; - if (!migration_in_postcopy() && - remaining_size < max_size) { + if (migrate_postcopy_ram()) { + /* We can do postcopy, and all the data is postcopiable */ + *res_postcopy_only += remaining_size; + } else { + *res_precopy_only += remaining_size; + } +} + +static void ram_state_pending_exact(void *opaque, uint64_t max_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) +{ + RAMState **temp = opaque; + RAMState *rs = *temp; + + uint64_t remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE; + + if (!migration_in_postcopy()) { qemu_mutex_lock_iothread(); WITH_RCU_READ_LOCK_GUARD() { migration_bitmap_sync_precopy(rs); @@ -4577,7 +4593,8 @@ static SaveVMHandlers savevm_ram_handlers = { .save_live_complete_postcopy = ram_save_complete, .save_live_complete_precopy = ram_save_complete, .has_postcopy = ram_has_postcopy, - .save_live_pending = ram_save_pending, + .state_pending_exact = ram_state_pending_exact, + .state_pending_estimate = ram_state_pending_estimate, .load_state = ram_load, .save_cleanup = ram_save_cleanup, .load_setup = ram_load_setup, diff --git a/migration/savevm.c b/migration/savevm.c index 5e4bccb966..7f9f770c1e 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1472,10 +1472,10 @@ flush: * the result is split into the amount for units that can and * for units that can't do postcopy. */ -void qemu_savevm_state_pending(uint64_t threshold_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only) +void qemu_savevm_state_pending_estimate(uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) { SaveStateEntry *se; @@ -1485,7 +1485,7 @@ void qemu_savevm_state_pending(uint64_t threshold_size, QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - if (!se->ops || !se->ops->save_live_pending) { + if (!se->ops || !se->ops->state_pending_exact) { continue; } if (se->ops->is_active) { @@ -1493,9 +1493,35 @@ void qemu_savevm_state_pending(uint64_t threshold_size, continue; } } - se->ops->save_live_pending(se->opaque, threshold_size, - res_precopy_only, res_compatible, - res_postcopy_only); + se->ops->state_pending_exact(se->opaque, threshold_size, + res_precopy_only, res_compatible, + res_postcopy_only); + } +} + +void qemu_savevm_state_pending_exact(uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) +{ + SaveStateEntry *se; + + *res_precopy_only = 0; + *res_compatible = 0; + *res_postcopy_only = 0; + + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + if (!se->ops || !se->ops->state_pending_estimate) { + continue; + } + if (se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } + se->ops->state_pending_estimate(se->opaque, threshold_size, + res_precopy_only, res_compatible, + res_postcopy_only); } } diff --git a/migration/savevm.h b/migration/savevm.h index 524cf12f25..5d2cff4411 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -40,10 +40,14 @@ void qemu_savevm_state_cleanup(void); void qemu_savevm_state_complete_postcopy(QEMUFile *f); int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, bool inactivate_disks); -void qemu_savevm_state_pending(uint64_t max_size, - uint64_t *res_precopy_only, - uint64_t *res_compatible, - uint64_t *res_postcopy_only); +void qemu_savevm_state_pending_exact(uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only); +void qemu_savevm_state_pending_estimate(uint64_t thershold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only); 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); diff --git a/migration/trace-events b/migration/trace-events index 57003edcbd..adb680b0e6 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -150,7 +150,8 @@ migrate_fd_cleanup(void) "" migrate_fd_error(const char *error_desc) "error=%s" migrate_fd_cancel(void) "" migrate_handle_rp_req_pages(const char *rbname, size_t start, size_t len) "in %s at 0x%zx len 0x%zx" -migrate_pending(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint64_t post) "pending size %" PRIu64 " max %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" +migrate_pending_exact(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint64_t post) "exact pending size %" PRIu64 " max %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" +migrate_pending_estimate(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint64_t post) "estimate pending size %" PRIu64 " max %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d" migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi64 migration_completion_file_err(void) "" @@ -330,7 +331,7 @@ send_bitmap_bits(uint32_t flags, uint64_t start_sector, uint32_t nr_sectors, uin dirty_bitmap_save_iterate(int in_postcopy) "in postcopy: %d" dirty_bitmap_save_complete_enter(void) "" dirty_bitmap_save_complete_finish(void) "" -dirty_bitmap_save_pending(uint64_t pending, uint64_t max_size) "pending %" PRIu64 " max: %" PRIu64 +dirty_bitmap_state_pending(uint64_t pending) "pending %" PRIu64 dirty_bitmap_load_complete(void) "" dirty_bitmap_load_bits_enter(uint64_t first_sector, uint32_t nr_sectors) "chunk: %" PRIu64 " %" PRIu32 dirty_bitmap_load_bits_zeroes(void) "" @@ -355,7 +356,7 @@ migration_block_save_device_dirty(int64_t sector) "Error reading sector %" PRId6 migration_block_flush_blks(const char *action, int submitted, int read_done, int transferred) "%s submitted %d read_done %d transferred %d" migration_block_save(const char *mig_stage, int submitted, int transferred) "Enter save live %s submitted %d transferred %d" migration_block_save_complete(void) "Block migration completed" -migration_block_save_pending(uint64_t pending) "Enter save live pending %" PRIu64 +migration_block_state_pending(uint64_t pending) "Enter save live pending %" PRIu64 # page_cache.c migration_pagecache_init(int64_t max_num_items) "Setting cache buckets to %" PRId64 From fd70385d38bb75128c1bdfc027af81cc41ec0e48 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 3 Oct 2022 02:50:42 +0200 Subject: [PATCH 542/814] migration: Remove unused threshold_size parameter Until previous commit, save_live_pending() was used for ram. Now with the split into state_pending_estimate() and state_pending_exact() it is not needed anymore, so remove them. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- hw/s390x/s390-stattrib.c | 2 +- hw/vfio/migration.c | 1 - include/migration/register.h | 2 -- migration/block-dirty-bitmap.c | 1 - migration/block.c | 2 +- migration/migration.c | 10 ++++------ migration/ram.c | 4 ++-- migration/savevm.c | 11 ++++------- migration/savevm.h | 6 ++---- migration/trace-events | 4 ++-- 10 files changed, 16 insertions(+), 27 deletions(-) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 8f573ebb10..3e32002eab 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -182,7 +182,7 @@ static int cmma_save_setup(QEMUFile *f, void *opaque) return 0; } -static void cmma_state_pending(void *opaque, uint64_t max_size, +static void cmma_state_pending(void *opaque, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index c49ca466d4..b3318f0f20 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -457,7 +457,6 @@ static void vfio_save_cleanup(void *opaque) } static void vfio_state_pending(void *opaque, - uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/include/migration/register.h b/include/migration/register.h index 15cf32994d..b91a0cdbf8 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -58,13 +58,11 @@ typedef struct SaveVMHandlers { */ /* This estimates the remaining data to transfer */ void (*state_pending_estimate)(void *opaque, - uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only); /* This calculate the exact remaining data to transfer */ void (*state_pending_exact)(void *opaque, - uint64_t threshold_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only); diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 6fac9fb34f..5a621419d3 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -763,7 +763,6 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) } static void dirty_bitmap_state_pending(void *opaque, - uint64_t max_size, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/migration/block.c b/migration/block.c index 544e74e9c5..29f69025af 100644 --- a/migration/block.c +++ b/migration/block.c @@ -863,7 +863,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) return 0; } -static void block_state_pending(void *opaque, uint64_t max_size, +static void block_state_pending(void *opaque, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/migration/migration.c b/migration/migration.c index 877a6f7011..7cab4b8192 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3781,18 +3781,16 @@ static MigIterateState migration_iteration_run(MigrationState *s) uint64_t pend_pre, pend_compat, pend_post; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; - qemu_savevm_state_pending_estimate(s->threshold_size, &pend_pre, - &pend_compat, &pend_post); + qemu_savevm_state_pending_estimate(&pend_pre, &pend_compat, &pend_post); uint64_t pending_size = pend_pre + pend_compat + pend_post; - trace_migrate_pending_estimate(pending_size, s->threshold_size, + trace_migrate_pending_estimate(pending_size, pend_pre, pend_compat, pend_post); if (pend_pre + pend_compat <= s->threshold_size) { - qemu_savevm_state_pending_exact(s->threshold_size, &pend_pre, - &pend_compat, &pend_post); + qemu_savevm_state_pending_exact(&pend_pre, &pend_compat, &pend_post); pending_size = pend_pre + pend_compat + pend_post; - trace_migrate_pending_exact(pending_size, s->threshold_size, + trace_migrate_pending_exact(pending_size, pend_pre, pend_compat, pend_post); } diff --git a/migration/ram.c b/migration/ram.c index 56ff9cd29d..885d7dbf23 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3409,7 +3409,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) return 0; } -static void ram_state_pending_estimate(void *opaque, uint64_t max_size, +static void ram_state_pending_estimate(void *opaque, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) @@ -3427,7 +3427,7 @@ static void ram_state_pending_estimate(void *opaque, uint64_t max_size, } } -static void ram_state_pending_exact(void *opaque, uint64_t max_size, +static void ram_state_pending_exact(void *opaque, uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) diff --git a/migration/savevm.c b/migration/savevm.c index 7f9f770c1e..e1caa3ea7c 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1472,8 +1472,7 @@ flush: * the result is split into the amount for units that can and * for units that can't do postcopy. */ -void qemu_savevm_state_pending_estimate(uint64_t threshold_size, - uint64_t *res_precopy_only, +void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) { @@ -1483,7 +1482,6 @@ void qemu_savevm_state_pending_estimate(uint64_t threshold_size, *res_compatible = 0; *res_postcopy_only = 0; - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || !se->ops->state_pending_exact) { continue; @@ -1493,14 +1491,13 @@ void qemu_savevm_state_pending_estimate(uint64_t threshold_size, continue; } } - se->ops->state_pending_exact(se->opaque, threshold_size, + se->ops->state_pending_exact(se->opaque, res_precopy_only, res_compatible, res_postcopy_only); } } -void qemu_savevm_state_pending_exact(uint64_t threshold_size, - uint64_t *res_precopy_only, +void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only) { @@ -1519,7 +1516,7 @@ void qemu_savevm_state_pending_exact(uint64_t threshold_size, continue; } } - se->ops->state_pending_estimate(se->opaque, threshold_size, + se->ops->state_pending_estimate(se->opaque, res_precopy_only, res_compatible, res_postcopy_only); } diff --git a/migration/savevm.h b/migration/savevm.h index 5d2cff4411..b1901e68d5 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -40,12 +40,10 @@ void qemu_savevm_state_cleanup(void); void qemu_savevm_state_complete_postcopy(QEMUFile *f); int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, bool inactivate_disks); -void qemu_savevm_state_pending_exact(uint64_t threshold_size, - uint64_t *res_precopy_only, +void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only); -void qemu_savevm_state_pending_estimate(uint64_t thershold_size, - uint64_t *res_precopy_only, +void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, uint64_t *res_compatible, uint64_t *res_postcopy_only); void qemu_savevm_send_ping(QEMUFile *f, uint32_t value); diff --git a/migration/trace-events b/migration/trace-events index adb680b0e6..67b65a70ff 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -150,8 +150,8 @@ migrate_fd_cleanup(void) "" migrate_fd_error(const char *error_desc) "error=%s" migrate_fd_cancel(void) "" migrate_handle_rp_req_pages(const char *rbname, size_t start, size_t len) "in %s at 0x%zx len 0x%zx" -migrate_pending_exact(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint64_t post) "exact pending size %" PRIu64 " max %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" -migrate_pending_estimate(uint64_t size, uint64_t max, uint64_t pre, uint64_t compat, uint64_t post) "estimate pending size %" PRIu64 " max %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" +migrate_pending_exact(uint64_t size, uint64_t pre, uint64_t compat, uint64_t post) "exact pending size %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" +migrate_pending_estimate(uint64_t size, uint64_t pre, uint64_t compat, uint64_t post) "estimate pending size %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d" migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi64 migration_completion_file_err(void) "" From d9df92925ef2b7ca8774ef44b0e1f859a91d4cd6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 3 Oct 2022 02:54:57 +0200 Subject: [PATCH 543/814] migration: simplify migration_iteration_run() Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- migration/migration.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 7cab4b8192..6d4cd8083b 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3794,23 +3794,23 @@ static MigIterateState migration_iteration_run(MigrationState *s) pend_pre, pend_compat, pend_post); } - if (pending_size && pending_size >= s->threshold_size) { - /* Still a significant amount to transfer */ - if (!in_postcopy && pend_pre <= s->threshold_size && - qatomic_read(&s->start_postcopy)) { - if (postcopy_start(s)) { - error_report("%s: postcopy failed to start", __func__); - } - return MIG_ITERATE_SKIP; - } - /* Just another iteration step */ - qemu_savevm_state_iterate(s->to_dst_file, in_postcopy); - } else { + if (!pending_size || pending_size < s->threshold_size) { trace_migration_thread_low_pending(pending_size); migration_completion(s); return MIG_ITERATE_BREAK; } + /* Still a significant amount to transfer */ + if (!in_postcopy && pend_pre <= s->threshold_size && + qatomic_read(&s->start_postcopy)) { + if (postcopy_start(s)) { + error_report("%s: postcopy failed to start", __func__); + } + return MIG_ITERATE_SKIP; + } + + /* Just another iteration step */ + qemu_savevm_state_iterate(s->to_dst_file, in_postcopy); return MIG_ITERATE_RESUME; } From d5890ea0722831eea76a0efd23a496b3e8815fe8 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 1 Feb 2023 16:10:54 -0500 Subject: [PATCH 544/814] util/userfaultfd: Add uffd_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a helper to create the uffd handle. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela --- include/qemu/userfaultfd.h | 12 ++++++++++++ migration/postcopy-ram.c | 11 +++++------ tests/qtest/migration-test.c | 4 ++-- util/userfaultfd.c | 13 +++++++++++-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/include/qemu/userfaultfd.h b/include/qemu/userfaultfd.h index 6b74f92792..d764496f0b 100644 --- a/include/qemu/userfaultfd.h +++ b/include/qemu/userfaultfd.h @@ -13,10 +13,20 @@ #ifndef USERFAULTFD_H #define USERFAULTFD_H +#ifdef CONFIG_LINUX + #include "qemu/osdep.h" #include "exec/hwaddr.h" #include +/** + * uffd_open(): Open an userfaultfd handle for current context. + * + * @flags: The flags we want to pass in when creating the handle. + * + * Returns: the uffd handle if >=0, or <0 if error happens. + */ +int uffd_open(int flags); int uffd_query_features(uint64_t *features); int uffd_create_fd(uint64_t features, bool non_blocking); void uffd_close_fd(int uffd_fd); @@ -32,4 +42,6 @@ int uffd_wakeup(int uffd_fd, void *addr, uint64_t length); int uffd_read_events(int uffd_fd, struct uffd_msg *msgs, int count); bool uffd_poll_events(int uffd_fd, int tmo); +#endif /* CONFIG_LINUX */ + #endif /* USERFAULTFD_H */ diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index b9a37ef255..0c55df0e52 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -37,6 +37,7 @@ #include "qemu-file.h" #include "yank_functions.h" #include "tls.h" +#include "qemu/userfaultfd.h" /* Arbitrary limit on size of each discard command, * keeps them around ~200 bytes @@ -226,11 +227,9 @@ static bool receive_ufd_features(uint64_t *features) int ufd; bool ret = true; - /* if we are here __NR_userfaultfd should exists */ - ufd = syscall(__NR_userfaultfd, O_CLOEXEC); + ufd = uffd_open(O_CLOEXEC); if (ufd == -1) { - error_report("%s: syscall __NR_userfaultfd failed: %s", __func__, - strerror(errno)); + error_report("%s: uffd_open() failed: %s", __func__, strerror(errno)); return false; } @@ -375,7 +374,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) goto out; } - ufd = syscall(__NR_userfaultfd, O_CLOEXEC); + ufd = uffd_open(O_CLOEXEC); if (ufd == -1) { error_report("%s: userfaultfd not available: %s", __func__, strerror(errno)); @@ -1160,7 +1159,7 @@ static int postcopy_temp_pages_setup(MigrationIncomingState *mis) int postcopy_ram_incoming_setup(MigrationIncomingState *mis) { /* Open the fd for the kernel to give us userfaults */ - mis->userfault_fd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + mis->userfault_fd = uffd_open(O_CLOEXEC | O_NONBLOCK); if (mis->userfault_fd == -1) { error_report("%s: Failed to open userfault fd: %s", __func__, strerror(errno)); diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 1dd32c9506..109bc8e7b1 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -61,14 +61,14 @@ static bool uffd_feature_thread_id; #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD) #include #include -#include +#include "qemu/userfaultfd.h" static bool ufd_version_check(void) { struct uffdio_api api_struct; uint64_t ioctl_mask; - int ufd = syscall(__NR_userfaultfd, O_CLOEXEC); + int ufd = uffd_open(O_CLOEXEC); if (ufd == -1) { g_test_message("Skipping test: userfaultfd not available"); diff --git a/util/userfaultfd.c b/util/userfaultfd.c index f1cd6af2b1..4953b3137d 100644 --- a/util/userfaultfd.c +++ b/util/userfaultfd.c @@ -19,6 +19,15 @@ #include #include +int uffd_open(int flags) +{ +#if defined(__NR_userfaultfd) + return syscall(__NR_userfaultfd, flags); +#else + return -EINVAL; +#endif +} + /** * uffd_query_features: query UFFD features * @@ -32,7 +41,7 @@ int uffd_query_features(uint64_t *features) struct uffdio_api api_struct = { 0 }; int ret = -1; - uffd_fd = syscall(__NR_userfaultfd, O_CLOEXEC); + uffd_fd = uffd_open(O_CLOEXEC); if (uffd_fd < 0) { trace_uffd_query_features_nosys(errno); return -1; @@ -69,7 +78,7 @@ int uffd_create_fd(uint64_t features, bool non_blocking) uint64_t ioctl_mask = BIT(_UFFDIO_REGISTER) | BIT(_UFFDIO_UNREGISTER); flags = O_CLOEXEC | (non_blocking ? O_NONBLOCK : 0); - uffd_fd = syscall(__NR_userfaultfd, flags); + uffd_fd = uffd_open(flags); if (uffd_fd < 0) { trace_uffd_create_fd_nosys(errno); return -1; From 5f19a4491941fdc5c5b50ce4ade6ffffe0f591b4 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Jan 2023 13:45:24 +0100 Subject: [PATCH 545/814] migration/ram: Fix populate_read_range() Unfortunately, commit f7b9dcfbcf44 broke populate_read_range(): the loop end condition is very wrong, resulting in that function not populating the full range. Lets' fix that. Fixes: f7b9dcfbcf44 ("migration/ram: Factor out populating pages readable in ram_block_populate_pages()") Cc: qemu-stable@nongnu.org Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/ram.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index 885d7dbf23..ba228eead4 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1774,13 +1774,15 @@ out: static inline void populate_read_range(RAMBlock *block, ram_addr_t offset, ram_addr_t size) { + const ram_addr_t end = offset + size; + /* * We read one byte of each page; this will preallocate page tables if * required and populate the shared zeropage on MAP_PRIVATE anonymous memory * where no page was populated yet. This might require adaption when * supporting other mappings, like shmem. */ - for (; offset < size; offset += block->page_size) { + for (; offset < end; offset += block->page_size) { char tmp = *((char *)block->host + offset); /* Don't optimize the read out */ From 72ef3a370836aa07261ad7aaeea27ed5cbcee342 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Jan 2023 13:45:25 +0100 Subject: [PATCH 546/814] migration/ram: Fix error handling in ram_write_tracking_start() If something goes wrong during uffd_change_protection(), we would miss to unregister uffd-wp and not release our reference. Fix it by performing the uffd_change_protection(true) last. Note that a uffd_change_protection(false) on the recovery path without a prior uffd_change_protection(false) is fine. Fixes: 278e2f551a09 ("migration: support UFFD write fault processing in ram_save_iterate()") Cc: qemu-stable@nongnu.org Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/ram.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index ba228eead4..73e5ca93e5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1896,13 +1896,14 @@ int ram_write_tracking_start(void) block->max_length, UFFDIO_REGISTER_MODE_WP, NULL)) { goto fail; } + block->flags |= RAM_UF_WRITEPROTECT; + memory_region_ref(block->mr); + /* Apply UFFD write protection to the block memory range */ if (uffd_change_protection(rs->uffdio_fd, block->host, block->max_length, true, false)) { goto fail; } - block->flags |= RAM_UF_WRITEPROTECT; - memory_region_ref(block->mr); trace_ram_write_tracking_ramblock_start(block->idstr, block->page_size, block->host, block->max_length); From 7cc8e9e0fadc734065d4d5c9cb0bd8997e743146 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Jan 2023 13:45:26 +0100 Subject: [PATCH 547/814] migration/ram: Don't explicitly unprotect when unregistering uffd-wp When unregistering uffd-wp, older kernels before commit f369b07c86143 ("mm/uffd:reset write protection when unregister with wp-mode") won't clear the uffd-wp PTE bit. When re-registering uffd-wp, the previous uffd-wp PTE bits would trigger again. With above commit, the kernel will clear the uffd-wp PTE bits when unregistering itself. Consequently, we'll clear the uffd-wp PTE bits now twice -- whereby we don't care about clearing them at all: a new background snapshot will re-register uffd-wp and re-protect all memory either way. So let's skip the manual clearing of uffd-wp. If ever relevant, we could clear conditionally in uffd_unregister_memory() -- we just need a way to figure out more recent kernels. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/ram.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 73e5ca93e5..efaae07dd8 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1918,12 +1918,6 @@ fail: if ((block->flags & RAM_UF_WRITEPROTECT) == 0) { continue; } - /* - * In case some memory block failed to be write-protected - * remove protection and unregister all succeeded RAM blocks - */ - uffd_change_protection(rs->uffdio_fd, block->host, block->max_length, - false, false); uffd_unregister_memory(rs->uffdio_fd, block->host, block->max_length); /* Cleanup flags and remove reference */ block->flags &= ~RAM_UF_WRITEPROTECT; @@ -1949,9 +1943,6 @@ void ram_write_tracking_stop(void) if ((block->flags & RAM_UF_WRITEPROTECT) == 0) { continue; } - /* Remove protection and unregister all affected RAM blocks */ - uffd_change_protection(rs->uffdio_fd, block->host, block->max_length, - false, false); uffd_unregister_memory(rs->uffdio_fd, block->host, block->max_length); trace_ram_write_tracking_ramblock_stop(block->idstr, block->page_size, From 59bcc049c17a50d8ac0353f164f597e7d904589d Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Jan 2023 13:45:27 +0100 Subject: [PATCH 548/814] migration/ram: Rely on used_length for uffd_change_protection() ram_mig_ram_block_resized() will abort migration (including background snapshots) when resizing a RAMBlock. ram_block_populate_read() will only populate RAM up to used_length, so at least for anonymous memory protecting everything between used_length and max_length won't actually be protected and is just a NOP. So let's only protect everything up to used_length. Note: it still makes sense to register uffd-wp for max_length, such that RAM_UF_WRITEPROTECT is independent of a changing used_length. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index efaae07dd8..a6956c9e7d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1901,7 +1901,7 @@ int ram_write_tracking_start(void) /* Apply UFFD write protection to the block memory range */ if (uffd_change_protection(rs->uffdio_fd, block->host, - block->max_length, true, false)) { + block->used_length, true, false)) { goto fail; } From e41c57702e940fcb9a8046edc3b43edda5134305 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Jan 2023 13:45:28 +0100 Subject: [PATCH 549/814] migration/ram: Optimize ram_write_tracking_start() for RamDiscardManager ram_block_populate_read() already optimizes for RamDiscardManager. However, ram_write_tracking_start() will still try protecting discarded memory ranges. Let's optimize, because discarded ranges don't map any pages and (1) For anonymous memory, trying to protect using uffd-wp without a mapped page is ignored by the kernel and consequently a NOP. (2) For shared/file-backed memory, we will fill present page tables in the range with PTE markers. However, we will even allocate page tables just to fill them with unnecessary PTE markers and effectively waste memory. So let's exclude these ranges, just like ram_block_populate_read() already does. Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/ram.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index a6956c9e7d..7f6d5efe8d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1865,6 +1865,39 @@ void ram_write_tracking_prepare(void) } } +static inline int uffd_protect_section(MemoryRegionSection *section, + void *opaque) +{ + const hwaddr size = int128_get64(section->size); + const hwaddr offset = section->offset_within_region; + RAMBlock *rb = section->mr->ram_block; + int uffd_fd = (uintptr_t)opaque; + + return uffd_change_protection(uffd_fd, rb->host + offset, size, true, + false); +} + +static int ram_block_uffd_protect(RAMBlock *rb, int uffd_fd) +{ + assert(rb->flags & RAM_UF_WRITEPROTECT); + + /* See ram_block_populate_read() */ + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { + RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = rb->mr->size, + }; + + return ram_discard_manager_replay_populated(rdm, §ion, + uffd_protect_section, + (void *)(uintptr_t)uffd_fd); + } + return uffd_change_protection(uffd_fd, rb->host, + rb->used_length, true, false); +} + /* * ram_write_tracking_start: start UFFD-WP memory tracking * @@ -1900,8 +1933,7 @@ int ram_write_tracking_start(void) memory_region_ref(block->mr); /* Apply UFFD write protection to the block memory range */ - if (uffd_change_protection(rs->uffdio_fd, block->host, - block->used_length, true, false)) { + if (ram_block_uffd_protect(block, uffd_fd)) { goto fail; } From 5e104f24e7ddfa33d5e99b6363c7baf02849f9b7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:42 +0100 Subject: [PATCH 550/814] migration/savevm: Move more savevm handling into vmstate_save() Let's move more code into vmstate_save(), reducing code duplication and preparing for reuse of vmstate_save() in qemu_savevm_state_setup(). We have to move vmstate_save() to make the compiler happy. We'll now also trace from qemu_save_device_state(), triggering the same tracepoints as previously called from qemu_savevm_state_complete_precopy_non_iterable() only. Note that qemu_save_device_state() ignores iterable device state, such as RAM, and consequently doesn't trigger some other trace points (e.g., trace_savevm_state_setup()). Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/savevm.c | 79 ++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index e1caa3ea7c..3e3631652e 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -898,17 +898,6 @@ static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se, } } -static int vmstate_save(QEMUFile *f, SaveStateEntry *se, - JSONWriter *vmdesc) -{ - trace_vmstate_save(se->idstr, se->vmsd ? se->vmsd->name : "(old)"); - if (!se->vmsd) { - vmstate_save_old_style(f, se, vmdesc); - return 0; - } - return vmstate_save_state(f, se->vmsd, se->opaque, vmdesc); -} - /* * Write the header for device section (QEMU_VM_SECTION START/END/PART/FULL) */ @@ -942,6 +931,43 @@ static void save_section_footer(QEMUFile *f, SaveStateEntry *se) } } +static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc) +{ + int ret; + + if ((!se->ops || !se->ops->save_state) && !se->vmsd) { + return 0; + } + if (se->vmsd && !vmstate_save_needed(se->vmsd, se->opaque)) { + trace_savevm_section_skip(se->idstr, se->section_id); + return 0; + } + + trace_savevm_section_start(se->idstr, se->section_id); + save_section_header(f, se, QEMU_VM_SECTION_FULL); + if (vmdesc) { + json_writer_start_object(vmdesc, NULL); + json_writer_str(vmdesc, "name", se->idstr); + json_writer_int64(vmdesc, "instance_id", se->instance_id); + } + + trace_vmstate_save(se->idstr, se->vmsd ? se->vmsd->name : "(old)"); + if (!se->vmsd) { + vmstate_save_old_style(f, se, vmdesc); + } else { + ret = vmstate_save_state(f, se->vmsd, se->opaque, vmdesc); + if (ret) { + return ret; + } + } + + trace_savevm_section_end(se->idstr, se->section_id, 0); + save_section_footer(f, se); + if (vmdesc) { + json_writer_end_object(vmdesc); + } + return 0; +} /** * qemu_savevm_command_send: Send a 'QEMU_VM_COMMAND' type element with the * command and associated data. @@ -1375,31 +1401,11 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, json_writer_int64(vmdesc, "page_size", qemu_target_page_size()); json_writer_start_array(vmdesc, "devices"); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - - if ((!se->ops || !se->ops->save_state) && !se->vmsd) { - continue; - } - if (se->vmsd && !vmstate_save_needed(se->vmsd, se->opaque)) { - trace_savevm_section_skip(se->idstr, se->section_id); - continue; - } - - trace_savevm_section_start(se->idstr, se->section_id); - - json_writer_start_object(vmdesc, NULL); - json_writer_str(vmdesc, "name", se->idstr); - json_writer_int64(vmdesc, "instance_id", se->instance_id); - - save_section_header(f, se, QEMU_VM_SECTION_FULL); ret = vmstate_save(f, se, vmdesc); if (ret) { qemu_file_set_error(f, ret); return ret; } - trace_savevm_section_end(se->idstr, se->section_id, 0); - save_section_footer(f, se); - - json_writer_end_object(vmdesc); } if (inactivate_disks) { @@ -1618,21 +1624,10 @@ int qemu_save_device_state(QEMUFile *f) if (se->is_ram) { continue; } - if ((!se->ops || !se->ops->save_state) && !se->vmsd) { - continue; - } - if (se->vmsd && !vmstate_save_needed(se->vmsd, se->opaque)) { - continue; - } - - save_section_header(f, se, QEMU_VM_SECTION_FULL); - ret = vmstate_save(f, se, NULL); if (ret) { return ret; } - - save_section_footer(f, se); } qemu_put_byte(f, QEMU_VM_EOF); From e3bf5e68e2a97898f37834c47449101172ced123 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:43 +0100 Subject: [PATCH 551/814] migration/savevm: Prepare vmdesc json writer in qemu_savevm_state_setup() ... and store it in the migration state. This is a preparation for storing selected vmds's already in qemu_savevm_state_setup(). Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- migration/migration.c | 2 ++ migration/migration.h | 4 ++++ migration/savevm.c | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 6d4cd8083b..c3ad4cd670 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1933,6 +1933,8 @@ static void migrate_fd_cleanup(MigrationState *s) g_free(s->hostname); s->hostname = NULL; + json_writer_free(s->vmdesc); + s->vmdesc = NULL; qemu_savevm_state_cleanup(); diff --git a/migration/migration.h b/migration/migration.h index ae4ffd3454..66511ce532 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -17,6 +17,7 @@ #include "exec/cpu-common.h" #include "hw/qdev-core.h" #include "qapi/qapi-types-migration.h" +#include "qapi/qmp/json-writer.h" #include "qemu/thread.h" #include "qemu/coroutine_int.h" #include "io/channel.h" @@ -366,6 +367,9 @@ struct MigrationState { * This save hostname when out-going migration starts */ char *hostname; + + /* QEMU_VM_VMDESCRIPTION content filled for all non-iterable devices. */ + JSONWriter *vmdesc; }; void migrate_set_state(int *state, int old_state, int new_state); diff --git a/migration/savevm.c b/migration/savevm.c index 3e3631652e..28f88b5521 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -42,7 +42,6 @@ #include "postcopy-ram.h" #include "qapi/error.h" #include "qapi/qapi-commands-migration.h" -#include "qapi/qmp/json-writer.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-builtin-visit.h" #include "qapi/qmp/qerror.h" @@ -1190,10 +1189,16 @@ bool qemu_savevm_state_guest_unplug_pending(void) void qemu_savevm_state_setup(QEMUFile *f) { + MigrationState *ms = migrate_get_current(); SaveStateEntry *se; Error *local_err = NULL; int ret; + ms->vmdesc = json_writer_new(false); + json_writer_start_object(ms->vmdesc, NULL); + json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size()); + json_writer_start_array(ms->vmdesc, "devices"); + trace_savevm_state_setup(); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || !se->ops->save_setup) { @@ -1391,15 +1396,12 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, bool in_postcopy, bool inactivate_disks) { - g_autoptr(JSONWriter) vmdesc = NULL; + MigrationState *ms = migrate_get_current(); + JSONWriter *vmdesc = ms->vmdesc; int vmdesc_len; SaveStateEntry *se; int ret; - vmdesc = json_writer_new(false); - json_writer_start_object(vmdesc, NULL); - json_writer_int64(vmdesc, "page_size", qemu_target_page_size()); - json_writer_start_array(vmdesc, "devices"); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { ret = vmstate_save(f, se, vmdesc); if (ret) { @@ -1434,6 +1436,10 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, qemu_put_buffer(f, (uint8_t *)json_writer_get(vmdesc), vmdesc_len); } + /* Free it now to detect any inconsistencies. */ + json_writer_free(vmdesc); + ms->vmdesc = NULL; + return 0; } From 62f42625d4e27a1993ab1999d0e86aedabf9a961 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:44 +0100 Subject: [PATCH 552/814] migration/savevm: Allow immutable device state to be migrated early (i.e., before RAM) For virtio-mem, we want to have the plugged/unplugged state of memory blocks available before migrating any actual RAM content, and perform sanity checks before touching anything on the destination. This information is immutable on the migration source while migration is active, We want to use this information for proper preallocation support with migration: currently, we don't preallocate memory on the migration target, and especially with hugetlb, we can easily run out of hugetlb pages during RAM migration and will crash (SIGBUS) instead of catching this gracefully via preallocation. Migrating device state via a VMSD before we start iterating is currently impossible: the only approach that would be possible is avoiding a VMSD and migrating state manually during save_setup(), to be restored during load_state(). Let's allow for migrating device state via a VMSD early, during the setup phase in qemu_savevm_state_setup(). To keep it simple, we indicate applicable VMSD's using an "early_setup" flag. Note that only very selected devices (i.e., ones seriously messing with RAM setup) are supposed to make use of such early state migration. While at it, also use a bool for the "unmigratable" member. Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 16 +++++++++++++++- migration/savevm.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index ad24aa1934..64680d824e 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -178,7 +178,21 @@ struct VMStateField { struct VMStateDescription { const char *name; - int unmigratable; + bool unmigratable; + /* + * This VMSD describes something that should be sent during setup phase + * of migration. It plays similar role as save_setup() for explicitly + * registered vmstate entries, so it can be seen as a way to describe + * save_setup() in VMSD structures. + * + * Note that for now, a SaveStateEntry cannot have a VMSD and + * operations (e.g., save_setup()) set at the same time. Consequently, + * save_setup() and a VMSD with early_setup set to true are mutually + * exclusive. For this reason, also early_setup VMSDs are migrated in a + * QEMU_VM_SECTION_FULL section, while save_setup() data is migrated in + * a QEMU_VM_SECTION_START section. + */ + bool early_setup; int version_id; int minimum_version_id; MigrationPriority priority; diff --git a/migration/savevm.c b/migration/savevm.c index 28f88b5521..6d985ad4af 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1201,6 +1201,15 @@ void qemu_savevm_state_setup(QEMUFile *f) trace_savevm_state_setup(); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + if (se->vmsd && se->vmsd->early_setup) { + ret = vmstate_save(f, se, ms->vmdesc); + if (ret) { + qemu_file_set_error(f, ret); + break; + } + continue; + } + if (!se->ops || !se->ops->save_setup) { continue; } @@ -1403,6 +1412,11 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, int ret; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + if (se->vmsd && se->vmsd->early_setup) { + /* Already saved during qemu_savevm_state_setup(). */ + continue; + } + ret = vmstate_save(f, se, vmdesc); if (ret) { qemu_file_set_error(f, ret); From 508f7988fd221f1f66c3f8a025c8a2dadac0af01 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:45 +0100 Subject: [PATCH 553/814] migration/vmstate: Introduce VMSTATE_WITH_TMP_TEST() and VMSTATE_BITMAP_TEST() We'll make use of both next in the context of virtio-mem. Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 64680d824e..28a3b92aa1 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -719,8 +719,9 @@ extern const VMStateInfo vmstate_info_qlist; * '_state' type * That the pointer is right at the start of _tmp_type. */ -#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) { \ +#define VMSTATE_WITH_TMP_TEST(_state, _test, _tmp_type, _vmsd) { \ .name = "tmp", \ + .field_exists = (_test), \ .size = sizeof(_tmp_type) + \ QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \ type_check_pointer(_state, \ @@ -729,6 +730,9 @@ extern const VMStateInfo vmstate_info_qlist; .info = &vmstate_info_tmp, \ } +#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \ + VMSTATE_WITH_TMP_TEST(_state, NULL, _tmp_type, _vmsd) + #define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \ .name = "unused", \ .field_exists = (_test), \ @@ -752,8 +756,9 @@ extern const VMStateInfo vmstate_info_qlist; /* _field_size should be a int32_t field in the _state struct giving the * size of the bitmap _field in bits. */ -#define VMSTATE_BITMAP(_field, _state, _version, _field_size) { \ +#define VMSTATE_BITMAP_TEST(_field, _state, _test, _version, _field_size) { \ .name = (stringify(_field)), \ + .field_exists = (_test), \ .version_id = (_version), \ .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\ .info = &vmstate_info_bitmap, \ @@ -761,6 +766,9 @@ extern const VMStateInfo vmstate_info_qlist; .offset = offsetof(_state, _field), \ } +#define VMSTATE_BITMAP(_field, _state, _version, _field_size) \ + VMSTATE_BITMAP_TEST(_field, _state, NULL, _version, _field_size) + /* For migrating a QTAILQ. * Target QTAILQ needs be properly initialized. * _type: type of QTAILQ element From 80fe315c384153af957ee94d43d08b90ad1d5ef7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:46 +0100 Subject: [PATCH 554/814] migration/ram: Factor out check for advised postcopy Let's factor out this check, to be used in virtio-mem context next. While at it, fix a spelling error in a related comment. Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- include/migration/misc.h | 4 +++- migration/migration.c | 7 +++++++ migration/ram.c | 8 +------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/migration/misc.h b/include/migration/misc.h index 465906710d..8b49841016 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -67,8 +67,10 @@ bool migration_has_failed(MigrationState *); /* ...and after the device transmission */ bool migration_in_postcopy_after_devices(MigrationState *); void migration_global_dump(Monitor *mon); -/* True if incomming migration entered POSTCOPY_INCOMING_DISCARD */ +/* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */ bool migration_in_incoming_postcopy(void); +/* True if incoming migration entered POSTCOPY_INCOMING_ADVISE */ +bool migration_incoming_postcopy_advised(void); /* True if background snapshot is active */ bool migration_in_bg_snapshot(void); diff --git a/migration/migration.c b/migration/migration.c index c3ad4cd670..f321e419c7 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2126,6 +2126,13 @@ bool migration_in_incoming_postcopy(void) return ps >= POSTCOPY_INCOMING_DISCARD && ps < POSTCOPY_INCOMING_END; } +bool migration_incoming_postcopy_advised(void) +{ + PostcopyState ps = postcopy_state_get(); + + return ps >= POSTCOPY_INCOMING_ADVISE && ps < POSTCOPY_INCOMING_END; +} + bool migration_in_bg_snapshot(void) { MigrationState *s = migrate_get_current(); diff --git a/migration/ram.c b/migration/ram.c index 7f6d5efe8d..b966e148c2 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4150,12 +4150,6 @@ int ram_load_postcopy(QEMUFile *f, int channel) return ret; } -static bool postcopy_is_advised(void) -{ - PostcopyState ps = postcopy_state_get(); - return ps >= POSTCOPY_INCOMING_ADVISE && ps < POSTCOPY_INCOMING_END; -} - static bool postcopy_is_running(void) { PostcopyState ps = postcopy_state_get(); @@ -4226,7 +4220,7 @@ static int ram_load_precopy(QEMUFile *f) MigrationIncomingState *mis = migration_incoming_get_current(); int flags = 0, ret = 0, invalid_flags = 0, len = 0, i = 0; /* ADVISE is earlier, it shows the source has the postcopy capability on */ - bool postcopy_advised = postcopy_is_advised(); + bool postcopy_advised = migration_incoming_postcopy_advised(); if (!migrate_use_compression()) { invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE; } From ce1761f0f9f0dde30a56cdcff68c034874fb91a0 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:47 +0100 Subject: [PATCH 555/814] virtio-mem: Fail if a memory backend with "prealloc=on" is specified "prealloc=on" for the memory backend does not work as expected, as virtio-mem will simply discard all preallocated memory immediately again. In the best case, it's an expensive NOP. In the worst case, it's an unexpected allocation error. Instead, "prealloc=on" should be specified for the virtio-mem device only, such that virtio-mem will try preallocating memory before plugging memory dynamically to the guest. Fail if such a memory backend is provided. Tested-by: Michal Privoznik Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- hw/virtio/virtio-mem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 1ed1f5a4af..02f7b5469a 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -772,6 +772,12 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "'%s' property specifies an unsupported memdev", VIRTIO_MEM_MEMDEV_PROP); return; + } else if (vmem->memdev->prealloc) { + error_setg(errp, "'%s' property specifies a memdev with preallocation" + " enabled: %s. Instead, specify 'prealloc=on' for the" + " virtio-mem device. ", VIRTIO_MEM_MEMDEV_PROP, + object_get_canonical_path_component(OBJECT(vmem->memdev))); + return; } if ((nb_numa_nodes && vmem->node >= nb_numa_nodes) || From 3b95a71b22827d261786b84f38b1e9109f6bf57b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:48 +0100 Subject: [PATCH 556/814] virtio-mem: Migrate immutable properties early The bitmap and the size are immutable while migration is active: see virtio_mem_is_busy(). We can migrate this information early, before migrating any actual RAM content. Further, all information we need for sanity checks is immutable as well. Having this information in place early will, for example, allow for properly preallocating memory before touching these memory locations during RAM migration: this way, we can make sure that all memory was actually preallocated and that any user errors (e.g., insufficient hugetlb pages) can be handled gracefully. In contrast, usable_region_size and requested_size can theoretically still be modified on the source while the VM is running. Keep migrating these properties the usual, late, way. Use a new device property to keep behavior of compat machines unmodified. Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- hw/core/machine.c | 4 ++- hw/virtio/virtio-mem.c | 51 ++++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-mem.h | 8 ++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index f7761baab5..b5cd42cd8c 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -41,7 +41,9 @@ #include "hw/virtio/virtio-pci.h" #include "qom/object_interfaces.h" -GlobalProperty hw_compat_7_2[] = {}; +GlobalProperty hw_compat_7_2[] = { + { "virtio-mem", "x-early-migration", "false" }, +}; const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2); GlobalProperty hw_compat_7_1[] = { diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 02f7b5469a..ca37949df8 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -31,6 +31,8 @@ #include CONFIG_DEVICES #include "trace.h" +static const VMStateDescription vmstate_virtio_mem_device_early; + /* * We only had legacy x86 guests that did not support * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests. @@ -878,6 +880,10 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) host_memory_backend_set_mapped(vmem->memdev, true); vmstate_register_ram(&vmem->memdev->mr, DEVICE(vmem)); + if (vmem->early_migration) { + vmstate_register(VMSTATE_IF(vmem), VMSTATE_INSTANCE_ID_ANY, + &vmstate_virtio_mem_device_early, vmem); + } qemu_register_reset(virtio_mem_system_reset, vmem); /* @@ -899,6 +905,10 @@ static void virtio_mem_device_unrealize(DeviceState *dev) */ memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); qemu_unregister_reset(virtio_mem_system_reset, vmem); + if (vmem->early_migration) { + vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early, + vmem); + } vmstate_unregister_ram(&vmem->memdev->mr, DEVICE(vmem)); host_memory_backend_set_mapped(vmem->memdev, false); virtio_del_queue(vdev, 0); @@ -1015,18 +1025,53 @@ static const VMStateDescription vmstate_virtio_mem_sanity_checks = { }, }; +static bool virtio_mem_vmstate_field_exists(void *opaque, int version_id) +{ + const VirtIOMEM *vmem = VIRTIO_MEM(opaque); + + /* With early migration, these fields were already migrated. */ + return !vmem->early_migration; +} + static const VMStateDescription vmstate_virtio_mem_device = { .name = "virtio-mem-device", .minimum_version_id = 1, .version_id = 1, .priority = MIG_PRI_VIRTIO_MEM, .post_load = virtio_mem_post_load, + .fields = (VMStateField[]) { + VMSTATE_WITH_TMP_TEST(VirtIOMEM, virtio_mem_vmstate_field_exists, + VirtIOMEMMigSanityChecks, + vmstate_virtio_mem_sanity_checks), + VMSTATE_UINT64(usable_region_size, VirtIOMEM), + VMSTATE_UINT64_TEST(size, VirtIOMEM, virtio_mem_vmstate_field_exists), + VMSTATE_UINT64(requested_size, VirtIOMEM), + VMSTATE_BITMAP_TEST(bitmap, VirtIOMEM, virtio_mem_vmstate_field_exists, + 0, bitmap_size), + VMSTATE_END_OF_LIST() + }, +}; + +/* + * Transfer properties that are immutable while migration is active early, + * such that we have have this information around before migrating any RAM + * content. + * + * Note that virtio_mem_is_busy() makes sure these properties can no longer + * change on the migration source until migration completed. + * + * With QEMU compat machines, we transmit these properties later, via + * vmstate_virtio_mem_device instead -- see virtio_mem_vmstate_field_exists(). + */ +static const VMStateDescription vmstate_virtio_mem_device_early = { + .name = "virtio-mem-device-early", + .minimum_version_id = 1, + .version_id = 1, + .early_setup = true, .fields = (VMStateField[]) { VMSTATE_WITH_TMP(VirtIOMEM, VirtIOMEMMigSanityChecks, vmstate_virtio_mem_sanity_checks), - VMSTATE_UINT64(usable_region_size, VirtIOMEM), VMSTATE_UINT64(size, VirtIOMEM), - VMSTATE_UINT64(requested_size, VirtIOMEM), VMSTATE_BITMAP(bitmap, VirtIOMEM, 0, bitmap_size), VMSTATE_END_OF_LIST() }, @@ -1211,6 +1256,8 @@ static Property virtio_mem_properties[] = { DEFINE_PROP_ON_OFF_AUTO(VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP, VirtIOMEM, unplugged_inaccessible, ON_OFF_AUTO_AUTO), #endif + DEFINE_PROP_BOOL(VIRTIO_MEM_EARLY_MIGRATION_PROP, VirtIOMEM, + early_migration, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h index 7745cfc1a3..f15e561785 100644 --- a/include/hw/virtio/virtio-mem.h +++ b/include/hw/virtio/virtio-mem.h @@ -31,6 +31,7 @@ OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass, #define VIRTIO_MEM_BLOCK_SIZE_PROP "block-size" #define VIRTIO_MEM_ADDR_PROP "memaddr" #define VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP "unplugged-inaccessible" +#define VIRTIO_MEM_EARLY_MIGRATION_PROP "x-early-migration" #define VIRTIO_MEM_PREALLOC_PROP "prealloc" struct VirtIOMEM { @@ -74,6 +75,13 @@ struct VirtIOMEM { /* whether to prealloc memory when plugging new blocks */ bool prealloc; + /* + * Whether we migrate properties that are immutable while migration is + * active early, before state of other devices and especially, before + * migrating any RAM content. + */ + bool early_migration; + /* notifiers to notify when "size" changes */ NotifierList size_change_notifiers; From d71920d42548d2bad17544cb488b09cece81a821 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 17 Jan 2023 12:22:49 +0100 Subject: [PATCH 557/814] virtio-mem: Proper support for preallocation with migration Ordinary memory preallocation runs when QEMU starts up and creates the memory backends, before processing the incoming migration stream. With virtio-mem, we don't know which memory blocks to preallocate before migration started. Now that we migrate the virtio-mem bitmap early, before migrating any RAM content, we can safely preallocate memory for all plugged memory blocks before migrating any RAM content. This is especially relevant for the following cases: (1) User errors With hugetlb/files, if we don't have sufficient backend memory available on the migration destination, we'll crash QEMU (SIGBUS) during RAM migration when running out of backend memory. Preallocating memory before actual RAM migration allows for failing gracefully and informing the user about the setup problem. (2) Excluded memory ranges during migration For example, virtio-balloon free page hinting will exclude some pages from getting migrated. In that case, we won't crash during RAM migration, but later, when running the VM on the destination, which is bad. To fix this for new QEMU machines that migrate the bitmap early, preallocate the memory early, before any RAM migration. Warn with old QEMU machines. Getting postcopy right is a bit tricky, but we essentially now implement the same (problematic) preallocation logic as ordinary preallocation: preallocate memory early and discard it again before precopy starts. During ordinary preallocation, discarding of RAM happens when postcopy is advised. As the state (bitmap) is loaded after postcopy was advised but before postcopy starts listening, we have to discard memory we preallocated immediately again ourselves. Note that nothing (not even hugetlb reservations) guarantees for postcopy that backend memory (especially, hugetlb pages) are still free after they were freed ones while discarding RAM. Still, allocating that memory at least once helps catching some basic setup problems. Before this change, trying to restore a VM when insufficient hugetlb pages are around results in the process crashing to to a "Bus error" (SIGBUS). With this change, QEMU fails gracefully: qemu-system-x86_64: qemu_prealloc_mem: preallocating memory failed: Bad address qemu-system-x86_64: error while loading state for instance 0x0 of device '0000:00:03.0/virtio-mem-device-early' qemu-system-x86_64: load of migration failed: Cannot allocate memory And we can even introspect the early migration data, including the bitmap: $ ./scripts/analyze-migration.py -f STATEFILE { "ram (2)": { "section sizes": { "0000:00:03.0/mem0": "0x0000000780000000", "0000:00:04.0/mem1": "0x0000000780000000", "pc.ram": "0x0000000100000000", "/rom@etc/acpi/tables": "0x0000000000020000", "pc.bios": "0x0000000000040000", "0000:00:02.0/e1000.rom": "0x0000000000040000", "pc.rom": "0x0000000000020000", "/rom@etc/table-loader": "0x0000000000001000", "/rom@etc/acpi/rsdp": "0x0000000000001000" } }, "0000:00:03.0/virtio-mem-device-early (51)": { "tmp": "00 00 00 01 40 00 00 00 00 00 00 07 80 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00", "size": "0x0000000040000000", "bitmap": "ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [...] }, "0000:00:04.0/virtio-mem-device-early (53)": { "tmp": "00 00 00 08 c0 00 00 00 00 00 00 07 80 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00", "size": "0x00000001fa400000", "bitmap": "ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [...] }, [...] Reported-by: Jing Qi Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Peter Xu Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela S Signed-off-by: David Hildenbrand Signed-off-by: Juan Quintela --- hw/virtio/virtio-mem.c | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index ca37949df8..957fe77dc0 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -204,6 +204,30 @@ static int virtio_mem_for_each_unplugged_range(const VirtIOMEM *vmem, void *arg, return ret; } +static int virtio_mem_for_each_plugged_range(const VirtIOMEM *vmem, void *arg, + virtio_mem_range_cb cb) +{ + unsigned long first_bit, last_bit; + uint64_t offset, size; + int ret = 0; + + first_bit = find_first_bit(vmem->bitmap, vmem->bitmap_size); + while (first_bit < vmem->bitmap_size) { + offset = first_bit * vmem->block_size; + last_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, + first_bit + 1) - 1; + size = (last_bit - first_bit + 1) * vmem->block_size; + + ret = cb(vmem, arg, offset, size); + if (ret) { + break; + } + first_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, + last_bit + 2); + } + return ret; +} + /* * Adjust the memory section to cover the intersection with the given range. * @@ -938,6 +962,10 @@ static int virtio_mem_post_load(void *opaque, int version_id) RamDiscardListener *rdl; int ret; + if (vmem->prealloc && !vmem->early_migration) { + warn_report("Proper preallocation with migration requires a newer QEMU machine"); + } + /* * We started out with all memory discarded and our memory region is mapped * into an address space. Replay, now that we updated the bitmap. @@ -957,6 +985,64 @@ static int virtio_mem_post_load(void *opaque, int version_id) return virtio_mem_restore_unplugged(vmem); } +static int virtio_mem_prealloc_range_cb(const VirtIOMEM *vmem, void *arg, + uint64_t offset, uint64_t size) +{ + void *area = memory_region_get_ram_ptr(&vmem->memdev->mr) + offset; + int fd = memory_region_get_fd(&vmem->memdev->mr); + Error *local_err = NULL; + + qemu_prealloc_mem(fd, area, size, 1, NULL, &local_err); + if (local_err) { + error_report_err(local_err); + return -ENOMEM; + } + return 0; +} + +static int virtio_mem_post_load_early(void *opaque, int version_id) +{ + VirtIOMEM *vmem = VIRTIO_MEM(opaque); + RAMBlock *rb = vmem->memdev->mr.ram_block; + int ret; + + if (!vmem->prealloc) { + return 0; + } + + /* + * We restored the bitmap and verified that the basic properties + * match on source and destination, so we can go ahead and preallocate + * memory for all plugged memory blocks, before actual RAM migration starts + * touching this memory. + */ + ret = virtio_mem_for_each_plugged_range(vmem, NULL, + virtio_mem_prealloc_range_cb); + if (ret) { + return ret; + } + + /* + * This is tricky: postcopy wants to start with a clean slate. On + * POSTCOPY_INCOMING_ADVISE, postcopy code discards all (ordinarily + * preallocated) RAM such that postcopy will work as expected later. + * + * However, we run after POSTCOPY_INCOMING_ADVISE -- but before actual + * RAM migration. So let's discard all memory again. This looks like an + * expensive NOP, but actually serves a purpose: we made sure that we + * were able to allocate all required backend memory once. We cannot + * guarantee that the backend memory we will free will remain free + * until we need it during postcopy, but at least we can catch the + * obvious setup issues this way. + */ + if (migration_incoming_postcopy_advised()) { + if (ram_block_discard_range(rb, 0, qemu_ram_get_used_length(rb))) { + return -EBUSY; + } + } + return 0; +} + typedef struct VirtIOMEMMigSanityChecks { VirtIOMEM *parent; uint64_t addr; @@ -1068,6 +1154,7 @@ static const VMStateDescription vmstate_virtio_mem_device_early = { .minimum_version_id = 1, .version_id = 1, .early_setup = true, + .post_load = virtio_mem_post_load_early, .fields = (VMStateField[]) { VMSTATE_WITH_TMP(VirtIOMEM, VirtIOMEMMigSanityChecks, vmstate_virtio_mem_sanity_checks), From db18dee7d7b069653ae748d68d9d99313dde74c4 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 15 Dec 2022 17:24:48 -0500 Subject: [PATCH 558/814] migration: Show downtime during postcopy phase The downtime should be displayed during postcopy phase because the switchover phase is done. OTOH it's weird to show "expected downtime" which can confuse what does that mean if the switchover has already happened anyway. This is a slight ABI change on QMP, but I assume it shouldn't affect anyone. Reviewed-by: Leonardo Bras Reviewed-by: Juan Quintela Signed-off-by: Peter Xu Signed-off-by: Juan Quintela --- migration/migration.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index f321e419c7..4f4d798d3e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1051,20 +1051,30 @@ bool migration_is_running(int state) } } +static bool migrate_show_downtime(MigrationState *s) +{ + return (s->state == MIGRATION_STATUS_COMPLETED) || migration_in_postcopy(); +} + static void populate_time_info(MigrationInfo *info, MigrationState *s) { info->has_status = true; info->has_setup_time = true; info->setup_time = s->setup_time; + if (s->state == MIGRATION_STATUS_COMPLETED) { info->has_total_time = true; info->total_time = s->total_time; - info->has_downtime = true; - info->downtime = s->downtime; } else { info->has_total_time = true; info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - s->start_time; + } + + if (migrate_show_downtime(s)) { + info->has_downtime = true; + info->downtime = s->downtime; + } else { info->has_expected_downtime = true; info->expected_downtime = s->expected_downtime; } From 74ecf6ac2b7e53cf480f1f2dc7a3af41525fb588 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 9 Dec 2022 14:15:24 +0100 Subject: [PATCH 559/814] migration/rdma: fix return value for qio_channel_rdma_{readv,writev} upon errors. As the documentation in include/io/channel.h states, only -1 and QIO_CHANNEL_ERR_BLOCK should be returned upon error. Other values have the potential to confuse the call sites. error_setg is used rather than error_setg_errno, because there are certain code paths where -1 (as a non-errno) is propagated up (e.g. starting from qemu_rdma_block_for_wrid or qemu_rdma_post_recv_control) all the way to qio_channel_rdma_{readv,writev}. Similar to a216ec85b7 ("migration/channel-block: fix return value for qio_channel_block_{readv,writev}"). Suggested-by: Zhang Chen Reviewed-by: Juan Quintela Signed-off-by: Fiona Ebner Signed-off-by: Juan Quintela --- migration/rdma.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 94a55dd95b..0ba1668d70 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2785,7 +2785,8 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { - return -EIO; + error_setg(errp, "RDMA control channel output is not set"); + return -1; } CHECK_ERROR_STATE(); @@ -2797,7 +2798,8 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, ret = qemu_rdma_write_flush(f, rdma); if (ret < 0) { rdma->error_state = ret; - return ret; + error_setg(errp, "qemu_rdma_write_flush returned %d", ret); + return -1; } for (i = 0; i < niov; i++) { @@ -2816,7 +2818,8 @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, if (ret < 0) { rdma->error_state = ret; - return ret; + error_setg(errp, "qemu_rdma_exchange_send returned %d", ret); + return -1; } data += len; @@ -2867,7 +2870,8 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { - return -EIO; + error_setg(errp, "RDMA control channel input is not set"); + return -1; } CHECK_ERROR_STATE(); @@ -2903,7 +2907,8 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, if (ret < 0) { rdma->error_state = ret; - return ret; + error_setg(errp, "qemu_rdma_exchange_recv returned %d", ret); + return -1; } /* From 89c568489122de996920b760c34e81b925cc8181 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Jan 2022 19:44:51 +0000 Subject: [PATCH 560/814] migration: Add canary to VMSTATE_END_OF_LIST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We fairly regularly forget VMSTATE_END_OF_LIST markers off descriptions; given that the current check is only for ->name being NULL, sometimes we get unlucky and the code apparently works and no one spots the error. Explicitly add a flag, VMS_END that should be set, and assert it is set during the traversal. Note: This can't go in until we update the copy of vmstate.h in slirp. Suggested-by: Peter Maydell Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 7 ++++++- migration/savevm.c | 1 + migration/vmstate.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 28a3b92aa1..084f5e784a 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -147,6 +147,9 @@ enum VMStateFlags { * VMStateField.struct_version_id to tell which version of the * structure we are referencing to use. */ VMS_VSTRUCT = 0x8000, + + /* Marker for end of list */ + VMS_END = 0x10000 }; typedef enum { @@ -1183,7 +1186,9 @@ extern const VMStateInfo vmstate_info_qlist; VMSTATE_UNUSED_BUFFER(_test, 0, _size) #define VMSTATE_END_OF_LIST() \ - {} + { \ + .flags = VMS_END, \ + } int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id); diff --git a/migration/savevm.c b/migration/savevm.c index 6d985ad4af..5c3e5b1bb5 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -585,6 +585,7 @@ static void dump_vmstate_vmsd(FILE *out_file, field++; first = false; } + assert(field->flags == VMS_END); fprintf(out_file, "\n%*s]", indent, ""); } if (vmsd->subsections != NULL) { diff --git a/migration/vmstate.c b/migration/vmstate.c index 924494bda3..83ca4c7d3e 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -154,6 +154,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, } field++; } + assert(field->flags == VMS_END); ret = vmstate_subsection_load(f, vmsd, opaque); if (ret != 0) { return ret; @@ -408,6 +409,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, } field++; } + assert(field->flags == VMS_END); if (vmdesc) { json_writer_end_array(vmdesc); From bb25a7289561d67133a7e7d69b15d81ead507a9e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Jan 2022 19:44:52 +0000 Subject: [PATCH 561/814] migration: Perform vmsd structure check during tests Perform a check on vmsd structures during test runs in the hope of catching any missing terminators and other simple screwups. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Peter Maydell Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/savevm.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/migration/savevm.c b/migration/savevm.c index 5c3e5b1bb5..e9cf4999ad 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -66,6 +66,7 @@ #include "net/announce.h" #include "qemu/yank.h" #include "yank_functions.h" +#include "sysemu/qtest.h" const unsigned int postcopy_ram_discard_version; @@ -804,6 +805,42 @@ void unregister_savevm(VMStateIf *obj, const char *idstr, void *opaque) } } +/* + * Perform some basic checks on vmsd's at registration + * time. + */ +static void vmstate_check(const VMStateDescription *vmsd) +{ + const VMStateField *field = vmsd->fields; + const VMStateDescription **subsection = vmsd->subsections; + + if (field) { + while (field->name) { + if (field->flags & (VMS_STRUCT | VMS_VSTRUCT)) { + /* Recurse to sub structures */ + vmstate_check(field->vmsd); + } + /* Carry on */ + field++; + } + /* Check for the end of field list canary */ + if (field->flags != VMS_END) { + error_report("VMSTATE not ending with VMS_END: %s", vmsd->name); + g_assert_not_reached(); + } + } + + while (subsection && *subsection) { + /* + * The name of a subsection should start with the name of the + * current object. + */ + assert(!strncmp(vmsd->name, (*subsection)->name, strlen(vmsd->name))); + vmstate_check(*subsection); + subsection++; + } +} + int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id, const VMStateDescription *vmsd, void *opaque, int alias_id, @@ -849,6 +886,11 @@ int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id, } else { se->instance_id = instance_id; } + + /* Perform a recursive sanity check during the test runs */ + if (qtest_enabled()) { + vmstate_check(vmsd); + } assert(!se->compat || se->instance_id == 0); savevm_state_handler_insert(se); return 0; From bd9510d38546a19aa2e58e1a94597acfb0fd82d4 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Tue, 29 Nov 2022 12:04:04 +0800 Subject: [PATCH 562/814] migration/dirtyrate: Show sample pages only in page-sampling mode The value of "Sample Pages" is confusing in mode other than page-sampling. See below: (qemu) calc_dirty_rate -b 10 520 (qemu) info dirty_rate Status: measuring Start Time: 11646834 (ms) Sample Pages: 520 (per GB) Period: 10 (sec) Mode: dirty-bitmap Dirty rate: (not ready) (qemu) info dirty_rate Status: measured Start Time: 11646834 (ms) Sample Pages: 0 (per GB) Period: 10 (sec) Mode: dirty-bitmap Dirty rate: 2 (MB/s) While it's totally useless in dirty-ring and dirty-bitmap mode, fix to show it only in page-sampling mode. Signed-off-by: Zhenzhong Duan Reviewed-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/dirtyrate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 4bfb97fc68..575d48c397 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -714,8 +714,8 @@ void qmp_calc_dirty_rate(int64_t calc_time, mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING; } - if (has_sample_pages && mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) { - error_setg(errp, "either sample-pages or dirty-ring can be specified."); + if (has_sample_pages && mode != DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING) { + error_setg(errp, "sample-pages is used only in page-sampling mode"); return; } @@ -785,8 +785,10 @@ void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict) DirtyRateStatus_str(info->status)); monitor_printf(mon, "Start Time: %"PRIi64" (ms)\n", info->start_time); - monitor_printf(mon, "Sample Pages: %"PRIu64" (per GB)\n", - info->sample_pages); + if (info->mode == DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING) { + monitor_printf(mon, "Sample Pages: %"PRIu64" (per GB)\n", + info->sample_pages); + } monitor_printf(mon, "Period: %"PRIi64" (sec)\n", info->calc_time); monitor_printf(mon, "Mode: %s\n", From 84615a19ddf2bfb38d7b3a0d487d2397ee55e4f3 Mon Sep 17 00:00:00 2001 From: "manish.mishra" Date: Tue, 20 Dec 2022 18:44:17 +0000 Subject: [PATCH 563/814] io: Add support for MSG_PEEK for socket channel MSG_PEEK peeks at the channel, The data is treated as unread and the next read shall still return this data. This support is currently added only for socket class. Extra parameter 'flags' is added to io_readv calls to pass extra read flags like MSG_PEEK. Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrange Reviewed-by: Juan Quintela Suggested-by: Daniel P. Berrange Signed-off-by: manish.mishra Signed-off-by: Juan Quintela --- chardev/char-socket.c | 4 ++-- include/io/channel.h | 6 ++++++ io/channel-buffer.c | 1 + io/channel-command.c | 1 + io/channel-file.c | 1 + io/channel-null.c | 1 + io/channel-socket.c | 19 ++++++++++++++++++- io/channel-tls.c | 1 + io/channel-websock.c | 1 + io/channel.c | 16 ++++++++++++---- migration/channel-block.c | 1 + migration/rdma.c | 1 + scsi/qemu-pr-helper.c | 2 +- tests/qtest/tpm-emu.c | 2 +- tests/unit/test-io-channel-socket.c | 1 + util/vhost-user-server.c | 2 +- 16 files changed, 50 insertions(+), 10 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 29ffe5075e..c2265436ac 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -283,11 +283,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len) if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { ret = qio_channel_readv_full(s->ioc, &iov, 1, &msgfds, &msgfds_num, - NULL); + 0, NULL); } else { ret = qio_channel_readv_full(s->ioc, &iov, 1, NULL, NULL, - NULL); + 0, NULL); } if (msgfds_num) { diff --git a/include/io/channel.h b/include/io/channel.h index 78b15f7870..153fbd2904 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -34,6 +34,8 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass, #define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1 +#define QIO_CHANNEL_READ_FLAG_MSG_PEEK 0x1 + typedef enum QIOChannelFeature QIOChannelFeature; enum QIOChannelFeature { @@ -41,6 +43,7 @@ enum QIOChannelFeature { QIO_CHANNEL_FEATURE_SHUTDOWN, QIO_CHANNEL_FEATURE_LISTEN, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY, + QIO_CHANNEL_FEATURE_READ_MSG_PEEK, }; @@ -114,6 +117,7 @@ struct QIOChannelClass { size_t niov, int **fds, size_t *nfds, + int flags, Error **errp); int (*io_close)(QIOChannel *ioc, Error **errp); @@ -188,6 +192,7 @@ void qio_channel_set_name(QIOChannel *ioc, * @niov: the length of the @iov array * @fds: pointer to an array that will received file handles * @nfds: pointer filled with number of elements in @fds on return + * @flags: read flags (QIO_CHANNEL_READ_FLAG_*) * @errp: pointer to a NULL-initialized error object * * Read data from the IO channel, storing it in the @@ -224,6 +229,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp); diff --git a/io/channel-buffer.c b/io/channel-buffer.c index bf52011be2..8096180f85 100644 --- a/io/channel-buffer.c +++ b/io/channel-buffer.c @@ -54,6 +54,7 @@ static ssize_t qio_channel_buffer_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc); diff --git a/io/channel-command.c b/io/channel-command.c index 74516252ba..e7edd091af 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -203,6 +203,7 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); diff --git a/io/channel-file.c b/io/channel-file.c index b67687c2aa..d76663e6ae 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -86,6 +86,7 @@ static ssize_t qio_channel_file_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc); diff --git a/io/channel-null.c b/io/channel-null.c index 75e3781507..4fafdb770d 100644 --- a/io/channel-null.c +++ b/io/channel-null.c @@ -60,6 +60,7 @@ qio_channel_null_readv(QIOChannel *ioc, size_t niov, int **fds G_GNUC_UNUSED, size_t *nfds G_GNUC_UNUSED, + int flags, Error **errp) { QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc); diff --git a/io/channel-socket.c b/io/channel-socket.c index b76dca9cc1..7aca84f61a 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -173,6 +173,9 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, } #endif + qio_channel_set_feature(QIO_CHANNEL(ioc), + QIO_CHANNEL_FEATURE_READ_MSG_PEEK); + return 0; } @@ -406,6 +409,9 @@ qio_channel_socket_accept(QIOChannelSocket *ioc, } #endif /* WIN32 */ + qio_channel_set_feature(QIO_CHANNEL(cioc), + QIO_CHANNEL_FEATURE_READ_MSG_PEEK); + trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd); return cioc; @@ -496,6 +502,7 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); @@ -517,6 +524,10 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc, } + if (flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) { + sflags |= MSG_PEEK; + } + retry: ret = recvmsg(sioc->fd, &msg, sflags); if (ret < 0) { @@ -624,11 +635,17 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); ssize_t done = 0; ssize_t i; + int sflags = 0; + + if (flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) { + sflags |= MSG_PEEK; + } for (i = 0; i < niov; i++) { ssize_t ret; @@ -636,7 +653,7 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc, ret = recv(sioc->fd, iov[i].iov_base, iov[i].iov_len, - 0); + sflags); if (ret < 0) { if (errno == EAGAIN) { if (done) { diff --git a/io/channel-tls.c b/io/channel-tls.c index 4ce890a538..c730cb8ec5 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -260,6 +260,7 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); diff --git a/io/channel-websock.c b/io/channel-websock.c index fb4932ade7..a12acc27cf 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -1081,6 +1081,7 @@ static ssize_t qio_channel_websock_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); diff --git a/io/channel.c b/io/channel.c index 0640941ac5..a8c7f11649 100644 --- a/io/channel.c +++ b/io/channel.c @@ -52,6 +52,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); @@ -63,7 +64,14 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc, return -1; } - return klass->io_readv(ioc, iov, niov, fds, nfds, errp); + if ((flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) && + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) { + error_setg_errno(errp, EINVAL, + "Channel does not support peek read"); + return -1; + } + + return klass->io_readv(ioc, iov, niov, fds, nfds, flags, errp); } @@ -146,7 +154,7 @@ int qio_channel_readv_full_all_eof(QIOChannel *ioc, while ((nlocal_iov > 0) || local_fds) { ssize_t len; len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds, - local_nfds, errp); + local_nfds, 0, errp); if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_IN); @@ -284,7 +292,7 @@ ssize_t qio_channel_readv(QIOChannel *ioc, size_t niov, Error **errp) { - return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp); + return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, 0, errp); } @@ -303,7 +311,7 @@ ssize_t qio_channel_read(QIOChannel *ioc, Error **errp) { struct iovec iov = { .iov_base = buf, .iov_len = buflen }; - return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp); + return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, 0, errp); } diff --git a/migration/channel-block.c b/migration/channel-block.c index f4ab53acdb..b7374363c3 100644 --- a/migration/channel-block.c +++ b/migration/channel-block.c @@ -53,6 +53,7 @@ qio_channel_block_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc); diff --git a/migration/rdma.c b/migration/rdma.c index 0ba1668d70..288eadc2d2 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2857,6 +2857,7 @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, size_t niov, int **fds, size_t *nfds, + int flags, Error **errp) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 196b78c00d..199227a556 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -614,7 +614,7 @@ static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz, iov.iov_base = buf; iov.iov_len = sz; n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1, - &fds, &nfds, errp); + &fds, &nfds, 0, errp); if (n_read == QIO_CHANNEL_ERR_BLOCK) { qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN); diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c index 73e0000a2c..f05fe12f01 100644 --- a/tests/qtest/tpm-emu.c +++ b/tests/qtest/tpm-emu.c @@ -115,7 +115,7 @@ void *tpm_emu_ctrl_thread(void *data) int *pfd = NULL; size_t nfd = 0; - qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort); + qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, 0, &error_abort); cmd = be32_to_cpu(cmd); g_assert_cmpint(cmd, ==, CMD_SET_DATAFD); g_assert_cmpint(nfd, ==, 1); diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index b36a5d972a..b964bb202d 100644 --- a/tests/unit/test-io-channel-socket.c +++ b/tests/unit/test-io-channel-socket.c @@ -460,6 +460,7 @@ static void test_io_channel_unix_fd_pass(void) G_N_ELEMENTS(iorecv), &fdrecv, &nfdrecv, + 0, &error_abort); g_assert(nfdrecv == G_N_ELEMENTS(fdsend)); diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index 232984ace6..145eb17c08 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -116,7 +116,7 @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg) * qio_channel_readv_full may have short reads, keeping calling it * until getting VHOST_USER_HDR_SIZE or 0 bytes in total */ - rc = qio_channel_readv_full(ioc, &iov, 1, &fds, &nfds, &local_err); + rc = qio_channel_readv_full(ioc, &iov, 1, &fds, &nfds, 0, &local_err); if (rc < 0) { if (rc == QIO_CHANNEL_ERR_BLOCK) { assert(local_err == NULL); From 6720c2b32725e6ac404f22851a0ecd0a71d0cbe2 Mon Sep 17 00:00:00 2001 From: "manish.mishra" Date: Tue, 20 Dec 2022 18:44:18 +0000 Subject: [PATCH 564/814] migration: check magic value for deciding the mapping of channels Current logic assumes that channel connections on the destination side are always established in the same order as the source and the first one will always be the main channel followed by the multifid or post-copy preemption channel. This may not be always true, as even if a channel has a connection established on the source side it can be in the pending state on the destination side and a newer connection can be established first. Basically causing out of order mapping of channels on the destination side. Currently, all channels except post-copy preempt send a magic number, this patch uses that magic number to decide the type of channel. This logic is applicable only for precopy(multifd) live migration, as mentioned, the post-copy preempt channel does not send any magic number. Also, tls live migrations already does tls handshake before creating other channels, so this issue is not possible with tls, hence this logic is avoided for tls live migrations. This patch uses read peek to check the magic number of channels so that current data/control stream management remains un-effected. Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrange Reviewed-by: Juan Quintela Suggested-by: Daniel P. Berrange Signed-off-by: manish.mishra Signed-off-by: Juan Quintela --- migration/channel.c | 45 +++++++++++++++++++++++++++++++++ migration/channel.h | 5 ++++ migration/migration.c | 54 ++++++++++++++++++++++++++++------------ migration/multifd.c | 19 +++++++------- migration/multifd.h | 2 +- migration/postcopy-ram.c | 5 +--- migration/postcopy-ram.h | 2 +- 7 files changed, 101 insertions(+), 31 deletions(-) diff --git a/migration/channel.c b/migration/channel.c index 1b0815039f..ca3319a309 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -92,3 +92,48 @@ void migration_channel_connect(MigrationState *s, migrate_fd_connect(s, error); error_free(error); } + + +/** + * @migration_channel_read_peek - Peek at migration channel, without + * actually removing it from channel buffer. + * + * @ioc: the channel object + * @buf: the memory region to read data into + * @buflen: the number of bytes to read in @buf + * @errp: pointer to a NULL-initialized error object + * + * Returns 0 if successful, returns -1 and sets @errp if fails. + */ +int migration_channel_read_peek(QIOChannel *ioc, + const char *buf, + const size_t buflen, + Error **errp) +{ + ssize_t len = 0; + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; + + while (true) { + len = qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, + QIO_CHANNEL_READ_FLAG_MSG_PEEK, errp); + + if (len <= 0 && len != QIO_CHANNEL_ERR_BLOCK) { + error_setg(errp, + "Failed to peek at channel"); + return -1; + } + + if (len == buflen) { + break; + } + + /* 1ms sleep. */ + if (qemu_in_coroutine()) { + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000); + } else { + g_usleep(1000); + } + } + + return 0; +} diff --git a/migration/channel.h b/migration/channel.h index 67a461c28a..5bdb8208a7 100644 --- a/migration/channel.h +++ b/migration/channel.h @@ -24,4 +24,9 @@ void migration_channel_connect(MigrationState *s, QIOChannel *ioc, const char *hostname, Error *error_in); + +int migration_channel_read_peek(QIOChannel *ioc, + const char *buf, + const size_t buflen, + Error **errp); #endif diff --git a/migration/migration.c b/migration/migration.c index 4f4d798d3e..66c74f8e17 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -31,6 +31,7 @@ #include "migration.h" #include "savevm.h" #include "qemu-file.h" +#include "channel.h" #include "migration/vmstate.h" #include "block/block.h" #include "qapi/error.h" @@ -664,10 +665,6 @@ static bool migration_incoming_setup(QEMUFile *f, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); - if (multifd_load_setup(errp) != 0) { - return false; - } - if (!mis->from_src_file) { mis->from_src_file = f; } @@ -734,31 +731,56 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); Error *local_err = NULL; - bool start_migration; QEMUFile *f; + bool default_channel = true; + uint32_t channel_magic = 0; + int ret = 0; - if (!mis->from_src_file) { - /* The first connection (multifd may have multiple) */ + if (migrate_use_multifd() && !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), &local_err); + + if (ret != 0) { + error_propagate(errp, local_err); + return; + } + + default_channel = (channel_magic == cpu_to_be32(QEMU_VM_FILE_MAGIC)); + } else { + default_channel = !mis->from_src_file; + } + + if (multifd_load_setup(errp) != 0) { + error_setg(errp, "Failed to setup multifd channels"); + return; + } + + if (default_channel) { f = qemu_file_new_input(ioc); if (!migration_incoming_setup(f, errp)) { return; } - - /* - * Common migration only needs one channel, so we can start - * right now. Some features need more than one channel, we wait. - */ - start_migration = !migration_needs_multiple_sockets(); } else { /* Multiple connections */ assert(migration_needs_multiple_sockets()); if (migrate_use_multifd()) { - start_migration = multifd_recv_new_channel(ioc, &local_err); + multifd_recv_new_channel(ioc, &local_err); } else { assert(migrate_postcopy_preempt()); f = qemu_file_new_input(ioc); - start_migration = postcopy_preempt_new_channel(mis, f); + postcopy_preempt_new_channel(mis, f); } if (local_err) { error_propagate(errp, local_err); @@ -766,7 +788,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) } } - if (start_migration) { + if (migration_has_all_channels()) { /* If it's a recovery, we're done */ if (postcopy_try_recover()) { return; diff --git a/migration/multifd.c b/migration/multifd.c index 000ca4d4ec..eeb4fb87ee 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1164,9 +1164,14 @@ int multifd_load_setup(Error **errp) uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); uint8_t i; - if (!migrate_use_multifd()) { + /* + * Return successfully if multiFD recv state is already initialised + * or multiFD is not enabled. + */ + if (multifd_recv_state || !migrate_use_multifd()) { return 0; } + if (!migrate_multi_channels_is_allowed()) { error_setg(errp, "multifd is not supported by current protocol"); return -1; @@ -1227,11 +1232,9 @@ bool multifd_recv_all_channels_created(void) /* * Try to receive all multifd channels to get ready for the migration. - * - Return true and do not set @errp when correctly receiving all channels; - * - Return false and do not set @errp when correctly receiving the current one; - * - Return false and set @errp when failing to receive the current channel. + * Sets @errp when failing to receive the current channel. */ -bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) +void multifd_recv_new_channel(QIOChannel *ioc, Error **errp) { MultiFDRecvParams *p; Error *local_err = NULL; @@ -1244,7 +1247,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) "failed to receive packet" " via multifd channel %d: ", qatomic_read(&multifd_recv_state->count)); - return false; + return; } trace_multifd_recv_new_channel(id); @@ -1254,7 +1257,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) id); multifd_recv_terminate_threads(local_err); error_propagate(errp, local_err); - return false; + return; } p->c = ioc; object_ref(OBJECT(ioc)); @@ -1265,6 +1268,4 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, QEMU_THREAD_JOINABLE); qatomic_inc(&multifd_recv_state->count); - return qatomic_read(&multifd_recv_state->count) == - migrate_multifd_channels(); } diff --git a/migration/multifd.h b/migration/multifd.h index e2802a9ce2..ff3aa2e2e9 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -18,7 +18,7 @@ void multifd_save_cleanup(void); int multifd_load_setup(Error **errp); int multifd_load_cleanup(Error **errp); bool multifd_recv_all_channels_created(void); -bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp); +void multifd_recv_new_channel(QIOChannel *ioc, Error **errp); void multifd_recv_sync_main(void); int multifd_send_sync_main(QEMUFile *f); int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset); diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 0c55df0e52..b98e95dab0 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1538,7 +1538,7 @@ void postcopy_unregister_shared_ufd(struct PostCopyFD *pcfd) } } -bool postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file) +void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file) { /* * The new loading channel has its own threads, so it needs to be @@ -1547,9 +1547,6 @@ bool postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file) qemu_file_set_blocking(file, true); mis->postcopy_qemufile_dst = file; trace_postcopy_preempt_new_channel(); - - /* Start the migration immediately */ - return true; } /* diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index 6147bf7d1d..25881c4127 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -190,7 +190,7 @@ enum PostcopyChannels { RAM_CHANNEL_MAX, }; -bool postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); +void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); int postcopy_preempt_setup(MigrationState *s, Error **errp); int postcopy_preempt_wait_channel(MigrationState *s); From ddbe628c97c3a2d211c6d96383cb4063ac3ad0f9 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 17 Oct 2022 15:53:50 +0800 Subject: [PATCH 565/814] multifd: Fix a race on reading MultiFDPages_t.block In multifd_queue_page() MultiFDPages_t.block is checked twice. Between the two checks, MultiFDPages_t.block may be reset to NULL by multifd thread. This lead to the 2nd check always true then a redundant page submitted to multifd thread again. Signed-off-by: Zhenzhong Duan Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/multifd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index eeb4fb87ee..ad89293b4e 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -442,6 +442,7 @@ static int multifd_send_pages(QEMUFile *f) int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) { MultiFDPages_t *pages = multifd_send_state->pages; + bool changed = false; if (!pages->block) { pages->block = block; @@ -454,14 +455,16 @@ int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) if (pages->num < pages->allocated) { return 1; } + } else { + changed = true; } if (multifd_send_pages(f) < 0) { return -1; } - if (pages->block != block) { - return multifd_queue_page(f, block, offset); + if (changed) { + return multifd_queue_page(f, block, offset); } return 1; From ebfc57871506b3fe36cc41f69ee3ad31a34afd63 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 17 Oct 2022 15:53:51 +0800 Subject: [PATCH 566/814] multifd: Fix flush of zero copy page send request Make IO channel flush call after the inflight request has been drained in multifd thread, or else we may missed to flush the inflight request. Signed-off-by: Zhenzhong Duan Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- .../x86_64-quintela-devices.mak | 7 + .../x86_64-quintela2-devices.mak | 6 + migration/multifd.c | 8 +- migration/multifd.c.orig | 1274 +++++++++++++++++ 4 files changed, 1291 insertions(+), 4 deletions(-) create mode 100644 configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak create mode 100644 configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak create mode 100644 migration/multifd.c.orig diff --git a/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak b/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak new file mode 100644 index 0000000000..ee2bb8c5c9 --- /dev/null +++ b/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak @@ -0,0 +1,7 @@ +# Boards: +# +CONFIG_ISAPC=n +CONFIG_I440FX=n +CONFIG_Q35=n +CONFIG_MICROVM=y + diff --git a/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak b/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak new file mode 100644 index 0000000000..f7e4dae842 --- /dev/null +++ b/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak @@ -0,0 +1,6 @@ +# Boards: +# +CONFIG_ISAPC=y +CONFIG_I440FX=y +CONFIG_Q35=y +CONFIG_MICROVM=y diff --git a/migration/multifd.c b/migration/multifd.c index ad89293b4e..437bf6f808 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -630,16 +630,16 @@ int multifd_send_sync_main(QEMUFile *f) stat64_add(&ram_atomic_counters.transferred, p->packet_len); qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); - - if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { - return -1; - } } for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; trace_multifd_send_sync_main_wait(p->id); qemu_sem_wait(&p->sem_sync); + + if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { + return -1; + } } trace_multifd_send_sync_main(multifd_send_state->packet_num); diff --git a/migration/multifd.c.orig b/migration/multifd.c.orig new file mode 100644 index 0000000000..ad89293b4e --- /dev/null +++ b/migration/multifd.c.orig @@ -0,0 +1,1274 @@ +/* + * Multifd common code + * + * Copyright (c) 2019-2020 Red Hat Inc + * + * Authors: + * Juan Quintela + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/rcu.h" +#include "exec/target_page.h" +#include "sysemu/sysemu.h" +#include "exec/ramblock.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "ram.h" +#include "migration.h" +#include "socket.h" +#include "tls.h" +#include "qemu-file.h" +#include "trace.h" +#include "multifd.h" + +#include "qemu/yank.h" +#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; + unsigned char uuid[16]; /* QemuUUID */ + uint8_t id; + uint8_t unused1[7]; /* Reserved for future use */ + uint64_t unused2[4]; /* Reserved for future use */ +} __attribute__((packed)) MultiFDInit_t; + +/* Multifd without compression */ + +/** + * nocomp_send_setup: setup send side + * + * For no compression this function does nothing. + * + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using + * @errp: pointer to an error + */ +static int nocomp_send_setup(MultiFDSendParams *p, Error **errp) +{ + return 0; +} + +/** + * nocomp_send_cleanup: cleanup send side + * + * For no compression this function does nothing. + * + * @p: Params for the channel that we are using + * @errp: pointer to an error + */ +static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) +{ + return; +} + +/** + * nocomp_send_prepare: prepare date to be able to send + * + * For no compression we just have to calculate the size of the + * packet. + * + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using + * @errp: pointer to an error + */ +static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) +{ + MultiFDPages_t *pages = p->pages; + + for (int i = 0; i < p->normal_num; i++) { + p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i]; + p->iov[p->iovs_num].iov_len = p->page_size; + p->iovs_num++; + } + + p->next_packet_size = p->normal_num * p->page_size; + p->flags |= MULTIFD_FLAG_NOCOMP; + return 0; +} + +/** + * nocomp_recv_setup: setup receive side + * + * For no compression this function does nothing. + * + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using + * @errp: pointer to an error + */ +static int nocomp_recv_setup(MultiFDRecvParams *p, Error **errp) +{ + return 0; +} + +/** + * nocomp_recv_cleanup: setup receive side + * + * For no compression this function does nothing. + * + * @p: Params for the channel that we are using + */ +static void nocomp_recv_cleanup(MultiFDRecvParams *p) +{ +} + +/** + * nocomp_recv_pages: read the data from the channel into actual pages + * + * For no compression we just need to read things into the correct place. + * + * Returns 0 for success or -1 for error + * + * @p: Params for the channel that we are using + * @errp: pointer to an error + */ +static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) +{ + uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; + + if (flags != MULTIFD_FLAG_NOCOMP) { + error_setg(errp, "multifd %u: flags received %x flags expected %x", + p->id, flags, MULTIFD_FLAG_NOCOMP); + return -1; + } + for (int i = 0; i < p->normal_num; i++) { + p->iov[i].iov_base = p->host + p->normal[i]; + p->iov[i].iov_len = p->page_size; + } + return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp); +} + +static MultiFDMethods multifd_nocomp_ops = { + .send_setup = nocomp_send_setup, + .send_cleanup = nocomp_send_cleanup, + .send_prepare = nocomp_send_prepare, + .recv_setup = nocomp_recv_setup, + .recv_cleanup = nocomp_recv_cleanup, + .recv_pages = nocomp_recv_pages +}; + +static MultiFDMethods *multifd_ops[MULTIFD_COMPRESSION__MAX] = { + [MULTIFD_COMPRESSION_NONE] = &multifd_nocomp_ops, +}; + +void multifd_register_ops(int method, MultiFDMethods *ops) +{ + assert(0 < method && method < MULTIFD_COMPRESSION__MAX); + multifd_ops[method] = ops; +} + +static int multifd_send_initial_packet(MultiFDSendParams *p, Error **errp) +{ + MultiFDInit_t msg = {}; + int ret; + + msg.magic = cpu_to_be32(MULTIFD_MAGIC); + msg.version = cpu_to_be32(MULTIFD_VERSION); + msg.id = p->id; + memcpy(msg.uuid, &qemu_uuid.data, sizeof(msg.uuid)); + + ret = qio_channel_write_all(p->c, (char *)&msg, sizeof(msg), errp); + if (ret != 0) { + return -1; + } + return 0; +} + +static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) +{ + MultiFDInit_t msg; + int ret; + + ret = qio_channel_read_all(c, (char *)&msg, sizeof(msg), errp); + if (ret != 0) { + return -1; + } + + msg.magic = be32_to_cpu(msg.magic); + msg.version = be32_to_cpu(msg.version); + + if (msg.magic != MULTIFD_MAGIC) { + error_setg(errp, "multifd: received packet magic %x " + "expected %x", msg.magic, MULTIFD_MAGIC); + return -1; + } + + if (msg.version != MULTIFD_VERSION) { + error_setg(errp, "multifd: received packet version %u " + "expected %u", msg.version, MULTIFD_VERSION); + return -1; + } + + if (memcmp(msg.uuid, &qemu_uuid, sizeof(qemu_uuid))) { + char *uuid = qemu_uuid_unparse_strdup(&qemu_uuid); + char *msg_uuid = qemu_uuid_unparse_strdup((const QemuUUID *)msg.uuid); + + error_setg(errp, "multifd: received uuid '%s' and expected " + "uuid '%s' for channel %hhd", msg_uuid, uuid, msg.id); + g_free(uuid); + g_free(msg_uuid); + return -1; + } + + if (msg.id > migrate_multifd_channels()) { + error_setg(errp, "multifd: received channel version %u " + "expected %u", msg.version, MULTIFD_VERSION); + return -1; + } + + return msg.id; +} + +static MultiFDPages_t *multifd_pages_init(size_t size) +{ + MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1); + + pages->allocated = size; + pages->offset = g_new0(ram_addr_t, size); + + return pages; +} + +static void multifd_pages_clear(MultiFDPages_t *pages) +{ + pages->num = 0; + pages->allocated = 0; + pages->packet_num = 0; + pages->block = NULL; + g_free(pages->offset); + pages->offset = NULL; + g_free(pages); +} + +static void multifd_send_fill_packet(MultiFDSendParams *p) +{ + MultiFDPacket_t *packet = p->packet; + int i; + + packet->flags = cpu_to_be32(p->flags); + packet->pages_alloc = cpu_to_be32(p->pages->allocated); + packet->normal_pages = cpu_to_be32(p->normal_num); + packet->next_packet_size = cpu_to_be32(p->next_packet_size); + packet->packet_num = cpu_to_be64(p->packet_num); + + if (p->pages->block) { + strncpy(packet->ramblock, p->pages->block->idstr, 256); + } + + for (i = 0; i < p->normal_num; i++) { + /* there are architectures where ram_addr_t is 32 bit */ + uint64_t temp = p->normal[i]; + + packet->offset[i] = cpu_to_be64(temp); + } +} + +static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) +{ + MultiFDPacket_t *packet = p->packet; + RAMBlock *block; + int i; + + packet->magic = be32_to_cpu(packet->magic); + if (packet->magic != MULTIFD_MAGIC) { + error_setg(errp, "multifd: received packet " + "magic %x and expected magic %x", + packet->magic, MULTIFD_MAGIC); + return -1; + } + + packet->version = be32_to_cpu(packet->version); + if (packet->version != MULTIFD_VERSION) { + error_setg(errp, "multifd: received packet " + "version %u and expected version %u", + packet->version, MULTIFD_VERSION); + return -1; + } + + p->flags = be32_to_cpu(packet->flags); + + packet->pages_alloc = be32_to_cpu(packet->pages_alloc); + /* + * If we received a packet that is 100 times bigger than expected + * just stop migration. It is a magic number. + */ + if (packet->pages_alloc > p->page_count) { + error_setg(errp, "multifd: received packet " + "with size %u and expected a size of %u", + packet->pages_alloc, p->page_count) ; + return -1; + } + + p->normal_num = be32_to_cpu(packet->normal_pages); + if (p->normal_num > packet->pages_alloc) { + error_setg(errp, "multifd: received packet " + "with %u pages and expected maximum pages are %u", + p->normal_num, packet->pages_alloc) ; + return -1; + } + + p->next_packet_size = be32_to_cpu(packet->next_packet_size); + p->packet_num = be64_to_cpu(packet->packet_num); + + if (p->normal_num == 0) { + return 0; + } + + /* make sure that ramblock is 0 terminated */ + packet->ramblock[255] = 0; + block = qemu_ram_block_by_name(packet->ramblock); + if (!block) { + error_setg(errp, "multifd: unknown ram block %s", + packet->ramblock); + return -1; + } + + p->host = block->host; + for (i = 0; i < p->normal_num; i++) { + uint64_t offset = be64_to_cpu(packet->offset[i]); + + if (offset > (block->used_length - p->page_size)) { + error_setg(errp, "multifd: offset too long %" PRIu64 + " (max " RAM_ADDR_FMT ")", + offset, block->used_length); + return -1; + } + p->normal[i] = offset; + } + + return 0; +} + +struct { + MultiFDSendParams *params; + /* array of pages to sent */ + MultiFDPages_t *pages; + /* global number of generated multifd packets */ + uint64_t packet_num; + /* send channels ready */ + QemuSemaphore channels_ready; + /* + * Have we already run terminate threads. There is a race when it + * happens that we got one error while we are exiting. + * We will use atomic operations. Only valid values are 0 and 1. + */ + int exiting; + /* multifd ops */ + MultiFDMethods *ops; +} *multifd_send_state; + +/* + * How we use multifd_send_state->pages and channel->pages? + * + * We create a pages for each channel, and a main one. Each time that + * we need to send a batch of pages we interchange the ones between + * multifd_send_state and the channel that is sending it. There are + * two reasons for that: + * - to not have to do so many mallocs during migration + * - to make easier to know what to free at the end of migration + * + * This way we always know who is the owner of each "pages" struct, + * and we don't need any locking. It belongs to the migration thread + * or to the channel thread. Switching is safe because the migration + * thread is using the channel mutex when changing it, and the channel + * have to had finish with its own, otherwise pending_job can't be + * false. + */ + +static int multifd_send_pages(QEMUFile *f) +{ + int i; + static int next_channel; + MultiFDSendParams *p = NULL; /* make happy gcc */ + MultiFDPages_t *pages = multifd_send_state->pages; + uint64_t transferred; + + if (qatomic_read(&multifd_send_state->exiting)) { + return -1; + } + + qemu_sem_wait(&multifd_send_state->channels_ready); + /* + * next_channel can remain from a previous migration that was + * using more channels, so ensure it doesn't overflow if the + * limit is lower now. + */ + next_channel %= migrate_multifd_channels(); + for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { + p = &multifd_send_state->params[i]; + + qemu_mutex_lock(&p->mutex); + if (p->quit) { + error_report("%s: channel %d has already quit!", __func__, i); + qemu_mutex_unlock(&p->mutex); + return -1; + } + if (!p->pending_job) { + p->pending_job++; + next_channel = (i + 1) % migrate_multifd_channels(); + break; + } + qemu_mutex_unlock(&p->mutex); + } + assert(!p->pages->num); + assert(!p->pages->block); + + p->packet_num = multifd_send_state->packet_num++; + multifd_send_state->pages = p->pages; + p->pages = pages; + transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len; + qemu_file_acct_rate_limit(f, transferred); + ram_counters.multifd_bytes += transferred; + stat64_add(&ram_atomic_counters.transferred, transferred); + qemu_mutex_unlock(&p->mutex); + qemu_sem_post(&p->sem); + + return 1; +} + +int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) +{ + MultiFDPages_t *pages = multifd_send_state->pages; + bool changed = false; + + if (!pages->block) { + pages->block = block; + } + + if (pages->block == block) { + pages->offset[pages->num] = offset; + pages->num++; + + if (pages->num < pages->allocated) { + return 1; + } + } else { + changed = true; + } + + if (multifd_send_pages(f) < 0) { + return -1; + } + + if (changed) { + return multifd_queue_page(f, block, offset); + } + + return 1; +} + +static void multifd_send_terminate_threads(Error *err) +{ + int i; + + trace_multifd_send_terminate_threads(err != NULL); + + if (err) { + MigrationState *s = migrate_get_current(); + migrate_set_error(s, err); + if (s->state == MIGRATION_STATUS_SETUP || + s->state == MIGRATION_STATUS_PRE_SWITCHOVER || + s->state == MIGRATION_STATUS_DEVICE || + s->state == MIGRATION_STATUS_ACTIVE) { + migrate_set_state(&s->state, s->state, + MIGRATION_STATUS_FAILED); + } + } + + /* + * We don't want to exit each threads twice. Depending on where + * we get the error, or if there are two independent errors in two + * threads at the same time, we can end calling this function + * twice. + */ + if (qatomic_xchg(&multifd_send_state->exiting, 1)) { + return; + } + + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + + qemu_mutex_lock(&p->mutex); + p->quit = true; + qemu_sem_post(&p->sem); + if (p->c) { + qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + } + qemu_mutex_unlock(&p->mutex); + } +} + +void multifd_save_cleanup(void) +{ + int i; + + if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { + return; + } + multifd_send_terminate_threads(NULL); + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + + if (p->running) { + qemu_thread_join(&p->thread); + } + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + Error *local_err = NULL; + + if (p->registered_yank) { + migration_ioc_unregister_yank(p->c); + } + socket_send_channel_destroy(p->c); + p->c = NULL; + qemu_mutex_destroy(&p->mutex); + qemu_sem_destroy(&p->sem); + qemu_sem_destroy(&p->sem_sync); + g_free(p->name); + p->name = NULL; + multifd_pages_clear(p->pages); + p->pages = NULL; + p->packet_len = 0; + g_free(p->packet); + p->packet = NULL; + g_free(p->iov); + p->iov = NULL; + g_free(p->normal); + p->normal = NULL; + multifd_send_state->ops->send_cleanup(p, &local_err); + if (local_err) { + migrate_set_error(migrate_get_current(), local_err); + error_free(local_err); + } + } + qemu_sem_destroy(&multifd_send_state->channels_ready); + g_free(multifd_send_state->params); + multifd_send_state->params = NULL; + multifd_pages_clear(multifd_send_state->pages); + multifd_send_state->pages = NULL; + g_free(multifd_send_state); + multifd_send_state = NULL; +} + +static int multifd_zero_copy_flush(QIOChannel *c) +{ + int ret; + Error *err = NULL; + + ret = qio_channel_flush(c, &err); + if (ret < 0) { + error_report_err(err); + return -1; + } + if (ret == 1) { + dirty_sync_missed_zero_copy(); + } + + return ret; +} + +int multifd_send_sync_main(QEMUFile *f) +{ + int i; + bool flush_zero_copy; + + if (!migrate_use_multifd()) { + return 0; + } + if (multifd_send_state->pages->num) { + if (multifd_send_pages(f) < 0) { + error_report("%s: multifd_send_pages fail", __func__); + return -1; + } + } + + /* + * When using zero-copy, it's necessary to flush the pages before any of + * the pages can be sent again, so we'll make sure the new version of the + * pages will always arrive _later_ than the old pages. + * + * Currently we achieve this by flushing the zero-page requested writes + * per ram iteration, but in the future we could potentially optimize it + * to be less frequent, e.g. only after we finished one whole scanning of + * all the dirty bitmaps. + */ + + flush_zero_copy = migrate_use_zero_copy_send(); + + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + + trace_multifd_send_sync_main_signal(p->id); + + qemu_mutex_lock(&p->mutex); + + if (p->quit) { + error_report("%s: channel %d has already quit", __func__, i); + qemu_mutex_unlock(&p->mutex); + return -1; + } + + p->packet_num = multifd_send_state->packet_num++; + p->flags |= MULTIFD_FLAG_SYNC; + p->pending_job++; + qemu_file_acct_rate_limit(f, p->packet_len); + ram_counters.multifd_bytes += p->packet_len; + stat64_add(&ram_atomic_counters.transferred, p->packet_len); + qemu_mutex_unlock(&p->mutex); + qemu_sem_post(&p->sem); + + if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { + return -1; + } + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + + trace_multifd_send_sync_main_wait(p->id); + qemu_sem_wait(&p->sem_sync); + } + trace_multifd_send_sync_main(multifd_send_state->packet_num); + + return 0; +} + +static void *multifd_send_thread(void *opaque) +{ + MultiFDSendParams *p = opaque; + Error *local_err = NULL; + int ret = 0; + bool use_zero_copy_send = migrate_use_zero_copy_send(); + + trace_multifd_send_thread_start(p->id); + rcu_register_thread(); + + if (multifd_send_initial_packet(p, &local_err) < 0) { + ret = -1; + goto out; + } + /* initial packet */ + p->num_packets = 1; + + while (true) { + qemu_sem_wait(&p->sem); + + if (qatomic_read(&multifd_send_state->exiting)) { + break; + } + qemu_mutex_lock(&p->mutex); + + if (p->pending_job) { + uint64_t packet_num = p->packet_num; + uint32_t flags = p->flags; + p->normal_num = 0; + + if (use_zero_copy_send) { + p->iovs_num = 0; + } else { + p->iovs_num = 1; + } + + for (int i = 0; i < p->pages->num; i++) { + p->normal[p->normal_num] = p->pages->offset[i]; + p->normal_num++; + } + + if (p->normal_num) { + ret = multifd_send_state->ops->send_prepare(p, &local_err); + if (ret != 0) { + qemu_mutex_unlock(&p->mutex); + break; + } + } + multifd_send_fill_packet(p); + p->flags = 0; + p->num_packets++; + p->total_normal_pages += p->normal_num; + p->pages->num = 0; + p->pages->block = NULL; + qemu_mutex_unlock(&p->mutex); + + trace_multifd_send(p->id, packet_num, p->normal_num, flags, + p->next_packet_size); + + if (use_zero_copy_send) { + /* Send header first, without zerocopy */ + ret = qio_channel_write_all(p->c, (void *)p->packet, + p->packet_len, &local_err); + if (ret != 0) { + break; + } + } else { + /* Send header using the same writev call */ + p->iov[0].iov_len = p->packet_len; + p->iov[0].iov_base = p->packet; + } + + ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, NULL, + 0, p->write_flags, &local_err); + if (ret != 0) { + break; + } + + qemu_mutex_lock(&p->mutex); + p->pending_job--; + qemu_mutex_unlock(&p->mutex); + + if (flags & MULTIFD_FLAG_SYNC) { + qemu_sem_post(&p->sem_sync); + } + qemu_sem_post(&multifd_send_state->channels_ready); + } else if (p->quit) { + qemu_mutex_unlock(&p->mutex); + break; + } else { + qemu_mutex_unlock(&p->mutex); + /* sometimes there are spurious wakeups */ + } + } + +out: + if (local_err) { + trace_multifd_send_error(p->id); + multifd_send_terminate_threads(local_err); + error_free(local_err); + } + + /* + * Error happen, I will exit, but I can't just leave, tell + * who pay attention to me. + */ + if (ret != 0) { + qemu_sem_post(&p->sem_sync); + qemu_sem_post(&multifd_send_state->channels_ready); + } + + qemu_mutex_lock(&p->mutex); + p->running = false; + qemu_mutex_unlock(&p->mutex); + + rcu_unregister_thread(); + trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages); + + return NULL; +} + +static bool multifd_channel_connect(MultiFDSendParams *p, + QIOChannel *ioc, + Error *error); + +static void multifd_tls_outgoing_handshake(QIOTask *task, + gpointer opaque) +{ + MultiFDSendParams *p = opaque; + QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); + Error *err = NULL; + + if (qio_task_propagate_error(task, &err)) { + trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err)); + } else { + trace_multifd_tls_outgoing_handshake_complete(ioc); + } + + if (!multifd_channel_connect(p, ioc, err)) { + /* + * Error happen, mark multifd_send_thread status as 'quit' although it + * is not created, and then tell who pay attention to me. + */ + p->quit = true; + qemu_sem_post(&multifd_send_state->channels_ready); + qemu_sem_post(&p->sem_sync); + } +} + +static void *multifd_tls_handshake_thread(void *opaque) +{ + MultiFDSendParams *p = opaque; + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(p->c); + + qio_channel_tls_handshake(tioc, + multifd_tls_outgoing_handshake, + p, + NULL, + NULL); + return NULL; +} + +static void multifd_tls_channel_connect(MultiFDSendParams *p, + QIOChannel *ioc, + Error **errp) +{ + MigrationState *s = migrate_get_current(); + const char *hostname = s->hostname; + QIOChannelTLS *tioc; + + tioc = migration_tls_client_create(s, ioc, hostname, errp); + if (!tioc) { + return; + } + + object_unref(OBJECT(ioc)); + trace_multifd_tls_outgoing_handshake_start(ioc, tioc, hostname); + qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); + p->c = QIO_CHANNEL(tioc); + qemu_thread_create(&p->thread, "multifd-tls-handshake-worker", + multifd_tls_handshake_thread, p, + QEMU_THREAD_JOINABLE); +} + +static bool multifd_channel_connect(MultiFDSendParams *p, + QIOChannel *ioc, + Error *error) +{ + trace_multifd_set_outgoing_channel( + ioc, object_get_typename(OBJECT(ioc)), + migrate_get_current()->hostname, error); + + if (!error) { + if (migrate_channel_requires_tls_upgrade(ioc)) { + multifd_tls_channel_connect(p, ioc, &error); + if (!error) { + /* + * tls_channel_connect will call back to this + * function after the TLS handshake, + * so we mustn't call multifd_send_thread until then + */ + return true; + } else { + return false; + } + } else { + migration_ioc_register_yank(ioc); + p->registered_yank = true; + p->c = ioc; + qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, + QEMU_THREAD_JOINABLE); + } + return true; + } + + return false; +} + +static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, + QIOChannel *ioc, Error *err) +{ + migrate_set_error(migrate_get_current(), err); + /* Error happen, we need to tell who pay attention to me */ + qemu_sem_post(&multifd_send_state->channels_ready); + qemu_sem_post(&p->sem_sync); + /* + * Although multifd_send_thread is not created, but main migration + * thread neet to judge whether it is running, so we need to mark + * its status. + */ + p->quit = true; + object_unref(OBJECT(ioc)); + error_free(err); +} + +static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) +{ + MultiFDSendParams *p = opaque; + QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); + Error *local_err = NULL; + + trace_multifd_new_send_channel_async(p->id); + if (qio_task_propagate_error(task, &local_err)) { + goto cleanup; + } else { + p->c = QIO_CHANNEL(sioc); + qio_channel_set_delay(p->c, false); + p->running = true; + if (!multifd_channel_connect(p, sioc, local_err)) { + goto cleanup; + } + return; + } + +cleanup: + multifd_new_send_channel_cleanup(p, sioc, local_err); +} + +int multifd_save_setup(Error **errp) +{ + int thread_count; + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint8_t i; + + if (!migrate_use_multifd()) { + return 0; + } + if (!migrate_multi_channels_is_allowed()) { + error_setg(errp, "multifd is not supported by current protocol"); + return -1; + } + + thread_count = migrate_multifd_channels(); + multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); + multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); + multifd_send_state->pages = multifd_pages_init(page_count); + qemu_sem_init(&multifd_send_state->channels_ready, 0); + qatomic_set(&multifd_send_state->exiting, 0); + multifd_send_state->ops = multifd_ops[migrate_multifd_compression()]; + + for (i = 0; i < thread_count; i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + + qemu_mutex_init(&p->mutex); + qemu_sem_init(&p->sem, 0); + qemu_sem_init(&p->sem_sync, 0); + p->quit = false; + p->pending_job = 0; + p->id = i; + p->pages = multifd_pages_init(page_count); + p->packet_len = sizeof(MultiFDPacket_t) + + sizeof(uint64_t) * page_count; + p->packet = g_malloc0(p->packet_len); + p->packet->magic = cpu_to_be32(MULTIFD_MAGIC); + p->packet->version = cpu_to_be32(MULTIFD_VERSION); + p->name = g_strdup_printf("multifdsend_%d", i); + /* We need one extra place for the packet header */ + p->iov = g_new0(struct iovec, page_count + 1); + p->normal = g_new0(ram_addr_t, page_count); + p->page_size = qemu_target_page_size(); + p->page_count = page_count; + + if (migrate_use_zero_copy_send()) { + p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; + } else { + p->write_flags = 0; + } + + socket_send_channel_create(multifd_new_send_channel_async, p); + } + + for (i = 0; i < thread_count; i++) { + MultiFDSendParams *p = &multifd_send_state->params[i]; + Error *local_err = NULL; + int ret; + + ret = multifd_send_state->ops->send_setup(p, &local_err); + if (ret) { + error_propagate(errp, local_err); + return ret; + } + } + return 0; +} + +struct { + MultiFDRecvParams *params; + /* number of created threads */ + int count; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; + /* global number of generated multifd packets */ + uint64_t packet_num; + /* multifd ops */ + MultiFDMethods *ops; +} *multifd_recv_state; + +static void multifd_recv_terminate_threads(Error *err) +{ + int i; + + trace_multifd_recv_terminate_threads(err != NULL); + + if (err) { + MigrationState *s = migrate_get_current(); + migrate_set_error(s, err); + if (s->state == MIGRATION_STATUS_SETUP || + s->state == MIGRATION_STATUS_ACTIVE) { + migrate_set_state(&s->state, s->state, + MIGRATION_STATUS_FAILED); + } + } + + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + qemu_mutex_lock(&p->mutex); + p->quit = true; + /* + * We could arrive here for two reasons: + * - normal quit, i.e. everything went fine, just finished + * - error quit: We close the channels so the channel threads + * finish the qio_channel_read_all_eof() + */ + if (p->c) { + qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + } + qemu_mutex_unlock(&p->mutex); + } +} + +int multifd_load_cleanup(Error **errp) +{ + int i; + + if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { + return 0; + } + multifd_recv_terminate_threads(NULL); + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + if (p->running) { + p->quit = true; + /* + * multifd_recv_thread may hung at MULTIFD_FLAG_SYNC handle code, + * however try to wakeup it without harm in cleanup phase. + */ + qemu_sem_post(&p->sem_sync); + qemu_thread_join(&p->thread); + } + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + migration_ioc_unregister_yank(p->c); + object_unref(OBJECT(p->c)); + p->c = NULL; + qemu_mutex_destroy(&p->mutex); + qemu_sem_destroy(&p->sem_sync); + g_free(p->name); + p->name = NULL; + p->packet_len = 0; + g_free(p->packet); + p->packet = NULL; + g_free(p->iov); + p->iov = NULL; + g_free(p->normal); + p->normal = NULL; + multifd_recv_state->ops->recv_cleanup(p); + } + qemu_sem_destroy(&multifd_recv_state->sem_sync); + g_free(multifd_recv_state->params); + multifd_recv_state->params = NULL; + g_free(multifd_recv_state); + multifd_recv_state = NULL; + + return 0; +} + +void multifd_recv_sync_main(void) +{ + int i; + + if (!migrate_use_multifd()) { + return; + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + trace_multifd_recv_sync_main_wait(p->id); + qemu_sem_wait(&multifd_recv_state->sem_sync); + } + for (i = 0; i < migrate_multifd_channels(); i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + WITH_QEMU_LOCK_GUARD(&p->mutex) { + if (multifd_recv_state->packet_num < p->packet_num) { + multifd_recv_state->packet_num = p->packet_num; + } + } + trace_multifd_recv_sync_main_signal(p->id); + qemu_sem_post(&p->sem_sync); + } + trace_multifd_recv_sync_main(multifd_recv_state->packet_num); +} + +static void *multifd_recv_thread(void *opaque) +{ + MultiFDRecvParams *p = opaque; + Error *local_err = NULL; + int ret; + + trace_multifd_recv_thread_start(p->id); + rcu_register_thread(); + + while (true) { + uint32_t flags; + + if (p->quit) { + break; + } + + ret = qio_channel_read_all_eof(p->c, (void *)p->packet, + p->packet_len, &local_err); + if (ret == 0) { /* EOF */ + break; + } + if (ret == -1) { /* Error */ + break; + } + + qemu_mutex_lock(&p->mutex); + ret = multifd_recv_unfill_packet(p, &local_err); + if (ret) { + qemu_mutex_unlock(&p->mutex); + break; + } + + flags = p->flags; + /* recv methods don't know how to handle the SYNC flag */ + p->flags &= ~MULTIFD_FLAG_SYNC; + trace_multifd_recv(p->id, p->packet_num, p->normal_num, flags, + p->next_packet_size); + p->num_packets++; + p->total_normal_pages += p->normal_num; + qemu_mutex_unlock(&p->mutex); + + if (p->normal_num) { + ret = multifd_recv_state->ops->recv_pages(p, &local_err); + if (ret != 0) { + break; + } + } + + if (flags & MULTIFD_FLAG_SYNC) { + qemu_sem_post(&multifd_recv_state->sem_sync); + qemu_sem_wait(&p->sem_sync); + } + } + + if (local_err) { + multifd_recv_terminate_threads(local_err); + error_free(local_err); + } + qemu_mutex_lock(&p->mutex); + p->running = false; + qemu_mutex_unlock(&p->mutex); + + rcu_unregister_thread(); + trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages); + + return NULL; +} + +int multifd_load_setup(Error **errp) +{ + int thread_count; + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint8_t i; + + /* + * Return successfully if multiFD recv state is already initialised + * or multiFD is not enabled. + */ + if (multifd_recv_state || !migrate_use_multifd()) { + return 0; + } + + if (!migrate_multi_channels_is_allowed()) { + error_setg(errp, "multifd is not supported by current protocol"); + return -1; + } + thread_count = migrate_multifd_channels(); + multifd_recv_state = g_malloc0(sizeof(*multifd_recv_state)); + multifd_recv_state->params = g_new0(MultiFDRecvParams, thread_count); + qatomic_set(&multifd_recv_state->count, 0); + qemu_sem_init(&multifd_recv_state->sem_sync, 0); + multifd_recv_state->ops = multifd_ops[migrate_multifd_compression()]; + + for (i = 0; i < thread_count; i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + + qemu_mutex_init(&p->mutex); + qemu_sem_init(&p->sem_sync, 0); + p->quit = false; + p->id = i; + p->packet_len = sizeof(MultiFDPacket_t) + + sizeof(uint64_t) * page_count; + p->packet = g_malloc0(p->packet_len); + p->name = g_strdup_printf("multifdrecv_%d", i); + p->iov = g_new0(struct iovec, page_count); + p->normal = g_new0(ram_addr_t, page_count); + p->page_count = page_count; + p->page_size = qemu_target_page_size(); + } + + for (i = 0; i < thread_count; i++) { + MultiFDRecvParams *p = &multifd_recv_state->params[i]; + Error *local_err = NULL; + int ret; + + ret = multifd_recv_state->ops->recv_setup(p, &local_err); + if (ret) { + error_propagate(errp, local_err); + return ret; + } + } + return 0; +} + +bool multifd_recv_all_channels_created(void) +{ + int thread_count = migrate_multifd_channels(); + + if (!migrate_use_multifd()) { + return true; + } + + if (!multifd_recv_state) { + /* Called before any connections created */ + return false; + } + + return thread_count == qatomic_read(&multifd_recv_state->count); +} + +/* + * Try to receive all multifd channels to get ready for the migration. + * Sets @errp when failing to receive the current channel. + */ +void multifd_recv_new_channel(QIOChannel *ioc, Error **errp) +{ + MultiFDRecvParams *p; + Error *local_err = NULL; + int id; + + id = multifd_recv_initial_packet(ioc, &local_err); + if (id < 0) { + multifd_recv_terminate_threads(local_err); + error_propagate_prepend(errp, local_err, + "failed to receive packet" + " via multifd channel %d: ", + qatomic_read(&multifd_recv_state->count)); + return; + } + trace_multifd_recv_new_channel(id); + + p = &multifd_recv_state->params[id]; + if (p->c != NULL) { + error_setg(&local_err, "multifd: received id '%d' already setup'", + id); + multifd_recv_terminate_threads(local_err); + error_propagate(errp, local_err); + return; + } + p->c = ioc; + object_ref(OBJECT(ioc)); + /* initial packet */ + p->num_packets = 1; + + p->running = true; + qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, + QEMU_THREAD_JOINABLE); + qatomic_inc(&multifd_recv_state->count); +} From 671326201dac8fe91222ba0045709f04a8ec3af4 Mon Sep 17 00:00:00 2001 From: Jiang Jiacheng Date: Fri, 3 Feb 2023 15:35:18 +0800 Subject: [PATCH 567/814] migration: Introduce interface query-migrationthreads Introduce interface query-migrationthreads. The interface is used to query information about migration threads and returns with migration thread's name and its id. Introduce threadinfo.c to manage threads with migration. Signed-off-by: Jiang Jiacheng Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/meson.build | 1 + migration/threadinfo.c | 51 ++++++++++++++++++++++++++++++++++++++++++ migration/threadinfo.h | 28 +++++++++++++++++++++++ qapi/migration.json | 29 ++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 migration/threadinfo.c create mode 100644 migration/threadinfo.h diff --git a/migration/meson.build b/migration/meson.build index a9e7e18793..0d1bb9f96e 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -26,6 +26,7 @@ softmmu_ss.add(files( 'savevm.c', 'socket.c', 'tls.c', + 'threadinfo.c', ), gnutls) softmmu_ss.add(when: rdma, if_true: files('rdma.c')) diff --git a/migration/threadinfo.c b/migration/threadinfo.c new file mode 100644 index 0000000000..1de8b31855 --- /dev/null +++ b/migration/threadinfo.c @@ -0,0 +1,51 @@ +/* + * Migration Threads info + * + * Copyright (c) 2022 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Jiang Jiacheng + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "threadinfo.h" + +static QLIST_HEAD(, MigrationThread) migration_threads; + +MigrationThread *MigrationThreadAdd(const char *name, int thread_id) +{ + MigrationThread *thread = g_new0(MigrationThread, 1); + thread->name = name; + thread->thread_id = thread_id; + + QLIST_INSERT_HEAD(&migration_threads, thread, node); + + return thread; +} + +void MigrationThreadDel(MigrationThread *thread) +{ + if (thread) { + QLIST_REMOVE(thread, node); + g_free(thread); + } +} + +MigrationThreadInfoList *qmp_query_migrationthreads(Error **errp) +{ + MigrationThreadInfoList *head = NULL; + MigrationThreadInfoList **tail = &head; + MigrationThread *thread = NULL; + + QLIST_FOREACH(thread, &migration_threads, node) { + MigrationThreadInfo *info = g_new0(MigrationThreadInfo, 1); + info->name = g_strdup(thread->name); + info->thread_id = thread->thread_id; + + QAPI_LIST_APPEND(tail, info); + } + + return head; +} diff --git a/migration/threadinfo.h b/migration/threadinfo.h new file mode 100644 index 0000000000..4d69423c0a --- /dev/null +++ b/migration/threadinfo.h @@ -0,0 +1,28 @@ +/* + * Migration Threads info + * + * Copyright (c) 2022 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Jiang Jiacheng + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/queue.h" +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-migration.h" + +typedef struct MigrationThread MigrationThread; + +struct MigrationThread { + const char *name; /* the name of migration thread */ + int thread_id; /* ID of the underlying host thread */ + QLIST_ENTRY(MigrationThread) node; +}; + +MigrationThread *MigrationThreadAdd(const char *name, int thread_id); + +void MigrationThreadDel(MigrationThread *info); diff --git a/qapi/migration.json b/qapi/migration.json index 88ecf86ac8..c84fa10e86 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1958,6 +1958,35 @@ { 'command': 'query-vcpu-dirty-limit', 'returns': [ 'DirtyLimitInfo' ] } +## +# @MigrationThreadInfo: +# +# Information about migrationthreads +# +# @name: the name of migration thread +# +# @thread-id: ID of the underlying host thread +# +# Since: 7.2 +## +{ 'struct': 'MigrationThreadInfo', + 'data': {'name': 'str', + 'thread-id': 'int'} } + +## +# @query-migrationthreads: +# +# Returns information of migration threads +# +# data: migration thread name +# +# returns: information about migration threads +# +# Since: 7.2 +## +{ 'command': 'query-migrationthreads', + 'returns': ['MigrationThreadInfo'] } + ## # @snapshot-save: # From 1b1f4ab69c41279a45ccd0d3178e83471e6e4ec1 Mon Sep 17 00:00:00 2001 From: Jiang Jiacheng Date: Fri, 3 Feb 2023 15:35:19 +0800 Subject: [PATCH 568/814] migration: save/delete migration thread info To support query migration thread infomation, save and delete thread(live_migration and multifdsend) information at thread creation and finish. Signed-off-by: Jiang Jiacheng Signed-off-by: Juan Quintela --- migration/migration.c | 5 +++++ migration/multifd.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 66c74f8e17..7a14aa98d8 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -58,6 +58,7 @@ #include "net/announce.h" #include "qemu/queue.h" #include "multifd.h" +#include "threadinfo.h" #include "qemu/yank.h" #include "sysemu/cpus.h" #include "yank_functions.h" @@ -4028,10 +4029,13 @@ static void qemu_savevm_wait_unplug(MigrationState *s, int old_state, static void *migration_thread(void *opaque) { MigrationState *s = opaque; + MigrationThread *thread = NULL; int64_t setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST); MigThrError thr_error; bool urgent = false; + thread = MigrationThreadAdd("live_migration", qemu_get_thread_id()); + rcu_register_thread(); object_ref(OBJECT(s)); @@ -4108,6 +4112,7 @@ static void *migration_thread(void *opaque) migration_iteration_finish(s); object_unref(OBJECT(s)); rcu_unregister_thread(); + MigrationThreadDel(thread); return NULL; } diff --git a/migration/multifd.c b/migration/multifd.c index 437bf6f808..b7ad7002e0 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -24,6 +24,7 @@ #include "qemu-file.h" #include "trace.h" #include "multifd.h" +#include "threadinfo.h" #include "qemu/yank.h" #include "io/channel-socket.h" @@ -649,10 +650,13 @@ int multifd_send_sync_main(QEMUFile *f) static void *multifd_send_thread(void *opaque) { MultiFDSendParams *p = opaque; + MigrationThread *thread = NULL; Error *local_err = NULL; int ret = 0; bool use_zero_copy_send = migrate_use_zero_copy_send(); + thread = MigrationThreadAdd(p->name, qemu_get_thread_id()); + trace_multifd_send_thread_start(p->id); rcu_register_thread(); @@ -762,6 +766,7 @@ out: qemu_mutex_unlock(&p->mutex); rcu_unregister_thread(); + MigrationThreadDel(thread); trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages); return NULL; From 3de1fb712a072992d72bc99c2b70978132ee44d0 Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Fri, 20 Jan 2023 16:15:51 +0100 Subject: [PATCH 569/814] target/riscv: update disas.c for xnor/orn/andn and slli.uw The decoding of the following instructions from Zb[abcs] currently contains decoding/printing errors: * xnor,orn,andn: the rs2 operand is not being printed * slli.uw: decodes and prints the immediate shift-amount as a register (e.g. 'shift-by-2' becomes 'sp') instead of interpreting this as an immediate This commit updates the instruction descriptions to use the appropriate decoding/printing formats. Signed-off-by: Philipp Tomsich Reviewed-by: Alistair Francis Message-Id: <20230120151551.1022761-1-philipp.tomsich@vrull.eu> Signed-off-by: Alistair Francis --- disas/riscv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index d216b9c39b..ddda687c13 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1626,9 +1626,9 @@ const rv_opcode_data opcode_data[] = { { "cpop", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, { "sext.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, { "sext.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "xnor", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "orn", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "andn", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "orn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "andn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "rol", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "ror", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, @@ -1647,7 +1647,7 @@ const rv_opcode_data opcode_data[] = { { "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, { "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, { "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "slli.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "slli.uw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, { "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, From 7ae714628745e28e0f1e2d5ad0f95b27a40ff5c2 Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Mon, 23 Jan 2023 16:36:21 +1000 Subject: [PATCH 570/814] include/hw/riscv/opentitan: update opentitan IRQs Updates the opentitan IRQs to match the latest supported commit of Opentitan from TockOS. OPENTITAN_SUPPORTED_SHA := 565e4af39760a123c59a184aa2f5812a961fde47 Memory layout as per [1] [1] https://github.com/lowRISC/opentitan/blob/565e4af39760a123c59a184aa2f5812a961fde47/hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h Signed-off-by: Wilfred Mallawa Reviewed-by: Alistair Francis Message-Id: <20230123063619.222459-1-wilfred.mallawa@opensource.wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/opentitan.c | 80 ++++++++++++++++++------------------ include/hw/riscv/opentitan.h | 14 +++---- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 64d5d435b9..353f030d80 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -31,47 +31,47 @@ /* * This version of the OpenTitan machine currently supports * OpenTitan RTL version: - * + * * * MMIO mapping as per (specified commit): * lowRISC/opentitan: hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h */ static const MemMapEntry ibex_memmap[] = { - [IBEX_DEV_ROM] = { 0x00008000, 0x8000 }, - [IBEX_DEV_RAM] = { 0x10000000, 0x20000 }, - [IBEX_DEV_FLASH] = { 0x20000000, 0x100000 }, - [IBEX_DEV_UART] = { 0x40000000, 0x1000 }, - [IBEX_DEV_GPIO] = { 0x40040000, 0x1000 }, - [IBEX_DEV_SPI_DEVICE] = { 0x40050000, 0x1000 }, - [IBEX_DEV_I2C] = { 0x40080000, 0x1000 }, - [IBEX_DEV_PATTGEN] = { 0x400e0000, 0x1000 }, - [IBEX_DEV_TIMER] = { 0x40100000, 0x1000 }, - [IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x4000 }, - [IBEX_DEV_LC_CTRL] = { 0x40140000, 0x1000 }, - [IBEX_DEV_ALERT_HANDLER] = { 0x40150000, 0x1000 }, - [IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x1000 }, - [IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x1000 }, - [IBEX_DEV_USBDEV] = { 0x40320000, 0x1000 }, - [IBEX_DEV_PWRMGR] = { 0x40400000, 0x1000 }, - [IBEX_DEV_RSTMGR] = { 0x40410000, 0x1000 }, - [IBEX_DEV_CLKMGR] = { 0x40420000, 0x1000 }, - [IBEX_DEV_PINMUX] = { 0x40460000, 0x1000 }, - [IBEX_DEV_AON_TIMER] = { 0x40470000, 0x1000 }, - [IBEX_DEV_SENSOR_CTRL] = { 0x40490000, 0x1000 }, - [IBEX_DEV_FLASH_CTRL] = { 0x41000000, 0x1000 }, - [IBEX_DEV_AES] = { 0x41100000, 0x1000 }, - [IBEX_DEV_HMAC] = { 0x41110000, 0x1000 }, - [IBEX_DEV_KMAC] = { 0x41120000, 0x1000 }, - [IBEX_DEV_OTBN] = { 0x41130000, 0x10000 }, - [IBEX_DEV_KEYMGR] = { 0x41140000, 0x1000 }, - [IBEX_DEV_CSRNG] = { 0x41150000, 0x1000 }, - [IBEX_DEV_ENTROPY] = { 0x41160000, 0x1000 }, - [IBEX_DEV_EDNO] = { 0x41170000, 0x1000 }, - [IBEX_DEV_EDN1] = { 0x41180000, 0x1000 }, - [IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 }, - [IBEX_DEV_PERI] = { 0x411f0000, 0x10000 }, - [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 }, - [IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 }, + [IBEX_DEV_ROM] = { 0x00008000, 0x8000 }, + [IBEX_DEV_RAM] = { 0x10000000, 0x20000 }, + [IBEX_DEV_FLASH] = { 0x20000000, 0x100000 }, + [IBEX_DEV_UART] = { 0x40000000, 0x40 }, + [IBEX_DEV_GPIO] = { 0x40040000, 0x40 }, + [IBEX_DEV_SPI_DEVICE] = { 0x40050000, 0x2000 }, + [IBEX_DEV_I2C] = { 0x40080000, 0x80 }, + [IBEX_DEV_PATTGEN] = { 0x400e0000, 0x40 }, + [IBEX_DEV_TIMER] = { 0x40100000, 0x200 }, + [IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x2000 }, + [IBEX_DEV_LC_CTRL] = { 0x40140000, 0x100 }, + [IBEX_DEV_ALERT_HANDLER] = { 0x40150000, 0x800 }, + [IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x40 }, + [IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x40 }, + [IBEX_DEV_USBDEV] = { 0x40320000, 0x1000 }, + [IBEX_DEV_PWRMGR] = { 0x40400000, 0x80 }, + [IBEX_DEV_RSTMGR] = { 0x40410000, 0x80 }, + [IBEX_DEV_CLKMGR] = { 0x40420000, 0x80 }, + [IBEX_DEV_PINMUX] = { 0x40460000, 0x1000 }, + [IBEX_DEV_AON_TIMER] = { 0x40470000, 0x40 }, + [IBEX_DEV_SENSOR_CTRL] = { 0x40490000, 0x40 }, + [IBEX_DEV_FLASH_CTRL] = { 0x41000000, 0x200 }, + [IBEX_DEV_AES] = { 0x41100000, 0x100 }, + [IBEX_DEV_HMAC] = { 0x41110000, 0x1000 }, + [IBEX_DEV_KMAC] = { 0x41120000, 0x1000 }, + [IBEX_DEV_OTBN] = { 0x41130000, 0x10000 }, + [IBEX_DEV_KEYMGR] = { 0x41140000, 0x100 }, + [IBEX_DEV_CSRNG] = { 0x41150000, 0x80 }, + [IBEX_DEV_ENTROPY] = { 0x41160000, 0x100 }, + [IBEX_DEV_EDNO] = { 0x41170000, 0x80 }, + [IBEX_DEV_EDN1] = { 0x41180000, 0x80 }, + [IBEX_DEV_SRAM_CTRL] = { 0x411c0000, 0x20 }, + [IBEX_DEV_IBEX_CFG] = { 0x411f0000, 0x100 }, + [IBEX_DEV_PLIC] = { 0x48000000, 0x8000000 }, + [IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 }, }; static void opentitan_board_init(MachineState *machine) @@ -294,12 +294,12 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) memmap[IBEX_DEV_EDN1].base, memmap[IBEX_DEV_EDN1].size); create_unimplemented_device("riscv.lowrisc.ibex.alert_handler", memmap[IBEX_DEV_ALERT_HANDLER].base, memmap[IBEX_DEV_ALERT_HANDLER].size); - create_unimplemented_device("riscv.lowrisc.ibex.nmi_gen", - memmap[IBEX_DEV_NMI_GEN].base, memmap[IBEX_DEV_NMI_GEN].size); + create_unimplemented_device("riscv.lowrisc.ibex.sram_ctrl", + memmap[IBEX_DEV_SRAM_CTRL].base, memmap[IBEX_DEV_SRAM_CTRL].size); create_unimplemented_device("riscv.lowrisc.ibex.otbn", memmap[IBEX_DEV_OTBN].base, memmap[IBEX_DEV_OTBN].size); - create_unimplemented_device("riscv.lowrisc.ibex.peri", - memmap[IBEX_DEV_PERI].base, memmap[IBEX_DEV_PERI].size); + create_unimplemented_device("riscv.lowrisc.ibex.ibex_cfg", + memmap[IBEX_DEV_IBEX_CFG].base, memmap[IBEX_DEV_IBEX_CFG].size); } static Property lowrisc_ibex_soc_props[] = { diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 7659d1bc5b..c40b05052a 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -94,9 +94,9 @@ enum { IBEX_DEV_EDNO, IBEX_DEV_EDN1, IBEX_DEV_ALERT_HANDLER, - IBEX_DEV_NMI_GEN, + IBEX_DEV_SRAM_CTRL, IBEX_DEV_OTBN, - IBEX_DEV_PERI, + IBEX_DEV_IBEX_CFG, }; enum { @@ -108,11 +108,11 @@ enum { IBEX_UART0_RX_BREAK_ERR_IRQ = 6, IBEX_UART0_RX_TIMEOUT_IRQ = 7, IBEX_UART0_RX_PARITY_ERR_IRQ = 8, - IBEX_TIMER_TIMEREXPIRED0_0 = 127, - IBEX_SPI_HOST0_ERR_IRQ = 134, - IBEX_SPI_HOST0_SPI_EVENT_IRQ = 135, - IBEX_SPI_HOST1_ERR_IRQ = 136, - IBEX_SPI_HOST1_SPI_EVENT_IRQ = 137, + IBEX_TIMER_TIMEREXPIRED0_0 = 124, + IBEX_SPI_HOST0_ERR_IRQ = 131, + IBEX_SPI_HOST0_SPI_EVENT_IRQ = 132, + IBEX_SPI_HOST1_ERR_IRQ = 133, + IBEX_SPI_HOST1_SPI_EVENT_IRQ = 134, }; #endif From 32c435a1ae9be183a309fb102d0fc38a4d2cd669 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 23 Jan 2023 13:57:54 +1000 Subject: [PATCH 571/814] hw/riscv: boot: Don't use CSRs if they are disabled If the CSRs and CSR instructions are disabled because the Zicsr extension isn't enabled then we want to make sure we don't run any CSR instructions in the boot ROM. This patches removes the CSR instructions from the reset-vec if the extension isn't enabled. We replace the instruction with a NOP instead. Note that we don't do this for the SiFive U machine, as we are modelling the hardware in that case. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1447 Signed-off-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-Id: <20230123035754.75553-1-alistair.francis@opensource.wdc.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 2594276223..cb27798a25 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -356,6 +356,15 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts reset_vec[4] = 0x0182b283; /* ld t0, 24(t0) */ } + if (!harts->harts[0].cfg.ext_icsr) { + /* + * The Zicsr extension has been disabled, so let's ensure we don't + * run the CSR instruction. Let's fill the address with a non + * compressed nop. + */ + reset_vec[2] = 0x00000013; /* addi x0, x0, 0 */ + } + /* copy in the reset vector in little_endian byte order */ for (i = 0; i < ARRAY_SIZE(reset_vec); i++) { reset_vec[i] = cpu_to_le32(reset_vec[i]); From 2cfb3b6c9b78fd9d47a2934ba53293c73c680406 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 20 Jan 2023 18:29:47 +0530 Subject: [PATCH 572/814] target/riscv: Update VS timer whenever htimedelta changes The htimedelta[h] CSR has impact on the VS timer comparison so we should call riscv_timer_write_timecmp() whenever htimedelta changes. Fixes: 3ec0fe18a31f ("target/riscv: Add vstimecmp suppor") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20230120125950.2246378-2-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 62e6c4acbd..fa17d7770c 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3045,6 +3045,8 @@ static RISCVException read_htimedelta(CPURISCVState *env, int csrno, static RISCVException write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) { + RISCVCPU *cpu = env_archcpu(env); + if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; } @@ -3054,6 +3056,12 @@ static RISCVException write_htimedelta(CPURISCVState *env, int csrno, } else { env->htimedelta = val; } + + if (cpu->cfg.ext_sstc && env->rdtime_fn) { + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + } + return RISCV_EXCP_NONE; } @@ -3071,11 +3079,19 @@ static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) { + RISCVCPU *cpu = env_archcpu(env); + if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; } env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); + + if (cpu->cfg.ext_sstc && env->rdtime_fn) { + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + } + return RISCV_EXCP_NONE; } From 14cb78bfaf4f99283252d9683ea4c0d97274ddea Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 20 Jan 2023 18:29:48 +0530 Subject: [PATCH 573/814] target/riscv: Don't clear mask in riscv_cpu_update_mip() for VSTIP Instead of clearing mask in riscv_cpu_update_mip() for VSTIP, we should call riscv_cpu_update_mip() with mask == 0 from timer_helper.c for VSTIP. Fixes: 3ec0fe18a31f ("target/riscv: Add vstimecmp suppor") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20230120125950.2246378-3-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 2 -- target/riscv/time_helper.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 9a28816521..0d72466f3b 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -621,8 +621,6 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; } - /* No need to update mip for VSTIP */ - mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask; vstip = env->vstime_irq ? MIP_VSTIP : 0; QEMU_IOTHREAD_LOCK_GUARD(); diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index 8cce667dfd..4fb2a471a9 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -27,7 +27,7 @@ static void riscv_vstimer_cb(void *opaque) RISCVCPU *cpu = opaque; CPURISCVState *env = &cpu->env; env->vstime_irq = 1; - riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1)); + riscv_cpu_update_mip(cpu, 0, BOOL_TO_MASK(1)); } static void riscv_stimer_cb(void *opaque) @@ -57,16 +57,20 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, */ if (timer_irq == MIP_VSTIP) { env->vstime_irq = 1; + riscv_cpu_update_mip(cpu, 0, BOOL_TO_MASK(1)); + } else { + riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1)); } - riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1)); return; } + /* Clear the [VS|S]TIP bit in mip */ if (timer_irq == MIP_VSTIP) { env->vstime_irq = 0; + riscv_cpu_update_mip(cpu, 0, BOOL_TO_MASK(0)); + } else { + riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); } - /* Clear the [V]STIP bit in mip */ - riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); /* otherwise, set up the future timer interrupt */ diff = timecmp - rtc_r; From ae0edf2188b3e4346b3e72bb69c75e70869e0c7f Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 20 Jan 2023 18:29:49 +0530 Subject: [PATCH 574/814] target/riscv: No need to re-start QEMU timer when timecmp == UINT64_MAX The time CSR will wrap-around immediately after reaching UINT64_MAX so we don't need to re-start QEMU timer when timecmp == UINT64_MAX in riscv_timer_write_timecmp(). Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20230120125950.2246378-4-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/time_helper.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index 4fb2a471a9..b654f91af9 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -72,6 +72,30 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); } + /* + * Sstc specification says the following about timer interrupt: + * "A supervisor timer interrupt becomes pending - as reflected in + * the STIP bit in the mip and sip registers - whenever time contains + * a value greater than or equal to stimecmp, treating the values + * as unsigned integers. Writes to stimecmp are guaranteed to be + * reflected in STIP eventually, but not necessarily immediately. + * The interrupt remains posted until stimecmp becomes greater + * than time - typically as a result of writing stimecmp." + * + * When timecmp = UINT64_MAX, the time CSR will eventually reach + * timecmp value but on next timer tick the time CSR will wrap-around + * and become zero which is less than UINT64_MAX. Now, the timer + * interrupt behaves like a level triggered interrupt so it will + * become 1 when time = timecmp = UINT64_MAX and next timer tick + * it will become 0 again because time = 0 < timecmp = UINT64_MAX. + * + * Based on above, we don't re-start the QEMU timer when timecmp + * equals UINT64_MAX. + */ + if (timecmp == UINT64_MAX) { + return; + } + /* otherwise, set up the future timer interrupt */ diff = timecmp - rtc_r; /* back to ns (note args switched in muldiv64) */ From f008a2d218d17b9be998be0045a7a3c229a3376d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 20 Jan 2023 18:29:50 +0530 Subject: [PATCH 575/814] target/riscv: Ensure opcode is saved for all relevant instructions We should call decode_save_opc() for all relevant instructions which can potentially generate a virtual instruction fault or a guest page fault because generating transformed instruction upon guest page fault expects opcode to be available. Without this, hypervisor will see transformed instruction as zero in htinst CSR for guest MMIO emulation which makes MMIO emulation in hypervisor slow and also breaks nested virtualization. Fixes: a9814e3e08d2 ("target/riscv: Minimize the calls to decode_save_opc") Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Message-Id: <20230120125950.2246378-5-apatel@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rva.c.inc | 10 +++++++--- target/riscv/insn_trans/trans_rvd.c.inc | 2 ++ target/riscv/insn_trans/trans_rvf.c.inc | 2 ++ target/riscv/insn_trans/trans_rvh.c.inc | 3 +++ target/riscv/insn_trans/trans_rvi.c.inc | 2 ++ target/riscv/insn_trans/trans_rvzfh.c.inc | 2 ++ target/riscv/insn_trans/trans_svinval.c.inc | 3 +++ 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index 45db82c9be..5f194a447b 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -20,8 +20,10 @@ static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop) { - TCGv src1 = get_address(ctx, a->rs1, 0); + TCGv src1; + decode_save_opc(ctx); + src1 = get_address(ctx, a->rs1, 0); if (a->rl) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } @@ -43,6 +45,7 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop) TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); + decode_save_opc(ctx); src1 = get_address(ctx, a->rs1, 0); tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1); @@ -81,9 +84,10 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv dest = dest_gpr(ctx, a->rd); - TCGv src1 = get_address(ctx, a->rs1, 0); - TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE); + decode_save_opc(ctx); + src1 = get_address(ctx, a->rs1, 0); func(dest, src1, src2, ctx->mem_idx, mop); gen_set_gpr(ctx, a->rd, dest); diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index 1397c1ce1c..6e3159b797 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -38,6 +38,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ); @@ -52,6 +53,7 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ); return true; diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index a1d3eb52ad..965e1f8d11 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -38,6 +38,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); dest = cpu_fpr[a->rd]; tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL); @@ -54,6 +55,7 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL); return true; diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc index 4f8aecddc7..9248b48c36 100644 --- a/target/riscv/insn_trans/trans_rvh.c.inc +++ b/target/riscv/insn_trans/trans_rvh.c.inc @@ -36,6 +36,7 @@ static bool do_hlv(DisasContext *ctx, arg_r2 *a, MemOp mop) #ifdef CONFIG_USER_ONLY return false; #else + decode_save_opc(ctx); if (check_access(ctx)) { TCGv dest = dest_gpr(ctx, a->rd); TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); @@ -82,6 +83,7 @@ static bool do_hsv(DisasContext *ctx, arg_r2_s *a, MemOp mop) #ifdef CONFIG_USER_ONLY return false; #else + decode_save_opc(ctx); if (check_access(ctx)) { TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); @@ -135,6 +137,7 @@ static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) static bool do_hlvx(DisasContext *ctx, arg_r2 *a, void (*func)(TCGv, TCGv_env, TCGv)) { + decode_save_opc(ctx); if (check_access(ctx)) { TCGv dest = dest_gpr(ctx, a->rd); TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 5c69b88d1e..4496f21266 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -261,6 +261,7 @@ static bool gen_load_i128(DisasContext *ctx, arg_lb *a, MemOp memop) static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { + decode_save_opc(ctx); if (get_xl(ctx) == MXL_RV128) { return gen_load_i128(ctx, a, memop); } else { @@ -350,6 +351,7 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop) static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) { + decode_save_opc(ctx); if (get_xl(ctx) == MXL_RV128) { return gen_store_i128(ctx, a, memop); } else { diff --git a/target/riscv/insn_trans/trans_rvzfh.c.inc b/target/riscv/insn_trans/trans_rvzfh.c.inc index 5d07150cd0..2ad5716312 100644 --- a/target/riscv/insn_trans/trans_rvzfh.c.inc +++ b/target/riscv/insn_trans/trans_rvzfh.c.inc @@ -49,6 +49,7 @@ static bool trans_flh(DisasContext *ctx, arg_flh *a) REQUIRE_FPU; REQUIRE_ZFH_OR_ZFHMIN(ctx); + decode_save_opc(ctx); t0 = get_gpr(ctx, a->rs1, EXT_NONE); if (a->imm) { TCGv temp = temp_new(ctx); @@ -71,6 +72,7 @@ static bool trans_fsh(DisasContext *ctx, arg_fsh *a) REQUIRE_FPU; REQUIRE_ZFH_OR_ZFHMIN(ctx); + decode_save_opc(ctx); t0 = get_gpr(ctx, a->rs1, EXT_NONE); if (a->imm) { TCGv temp = tcg_temp_new(); diff --git a/target/riscv/insn_trans/trans_svinval.c.inc b/target/riscv/insn_trans/trans_svinval.c.inc index 2682bd969f..f3cd7d5c0b 100644 --- a/target/riscv/insn_trans/trans_svinval.c.inc +++ b/target/riscv/insn_trans/trans_svinval.c.inc @@ -28,6 +28,7 @@ static bool trans_sinval_vma(DisasContext *ctx, arg_sinval_vma *a) /* Do the same as sfence.vma currently */ REQUIRE_EXT(ctx, RVS); #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_tlb_flush(cpu_env); return true; #endif @@ -56,6 +57,7 @@ static bool trans_hinval_vvma(DisasContext *ctx, arg_hinval_vvma *a) /* Do the same as hfence.vvma currently */ REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_hyp_tlb_flush(cpu_env); return true; #endif @@ -68,6 +70,7 @@ static bool trans_hinval_gvma(DisasContext *ctx, arg_hinval_gvma *a) /* Do the same as hfence.gvma currently */ REQUIRE_EXT(ctx, RVH); #ifndef CONFIG_USER_ONLY + decode_save_opc(ctx); gen_helper_hyp_gvma_tlb_flush(cpu_env); return true; #endif From 2967f37d448b86cc5b9a89d83a4e0f4ec01856be Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 24 Jan 2023 18:22:32 -0300 Subject: [PATCH 576/814] hw/riscv/virt.c: calculate socket count once in create_fdt_imsic() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit riscv_socket_count() returns either ms->numa_state->num_nodes or 1 depending on NUMA support. In any case the value can be retrieved only once and used in the rest of the function. This will also alleviate the rename we're going to do next by reducing the instances of MachineState 'mc' inside hw/riscv/virt.c. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Signed-off-by: Daniel Henrique Barboza Message-Id: <20230124212234.412630-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 4a11b4b010..61fdb52090 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -505,13 +505,14 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, int cpu, socket; char *imsic_name; MachineState *mc = MACHINE(s); + int socket_count = riscv_socket_count(mc); uint32_t imsic_max_hart_per_socket, imsic_guest_bits; uint32_t *imsic_cells, *imsic_regs, imsic_addr, imsic_size; *msi_m_phandle = (*phandle)++; *msi_s_phandle = (*phandle)++; imsic_cells = g_new0(uint32_t, mc->smp.cpus * 2); - imsic_regs = g_new0(uint32_t, riscv_socket_count(mc) * 4); + imsic_regs = g_new0(uint32_t, socket_count * 4); /* M-level IMSIC node */ for (cpu = 0; cpu < mc->smp.cpus; cpu++) { @@ -519,7 +520,7 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT); } imsic_max_hart_per_socket = 0; - for (socket = 0; socket < riscv_socket_count(mc); socket++) { + for (socket = 0; socket < socket_count; socket++) { imsic_addr = memmap[VIRT_IMSIC_M].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE; imsic_size = IMSIC_HART_SIZE(0) * s->soc[socket].num_harts; @@ -545,14 +546,14 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop(mc->fdt, imsic_name, "interrupts-extended", imsic_cells, mc->smp.cpus * sizeof(uint32_t) * 2); qemu_fdt_setprop(mc->fdt, imsic_name, "reg", imsic_regs, - riscv_socket_count(mc) * sizeof(uint32_t) * 4); + socket_count * sizeof(uint32_t) * 4); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); - if (riscv_socket_count(mc) > 1) { + if (socket_count > 1) { qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits", imsic_num_bits(imsic_max_hart_per_socket)); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-bits", - imsic_num_bits(riscv_socket_count(mc))); + imsic_num_bits(socket_count)); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-shift", IMSIC_MMIO_GROUP_MIN_SHIFT); } @@ -567,7 +568,7 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, } imsic_guest_bits = imsic_num_bits(s->aia_guests + 1); imsic_max_hart_per_socket = 0; - for (socket = 0; socket < riscv_socket_count(mc); socket++) { + for (socket = 0; socket < socket_count; socket++) { imsic_addr = memmap[VIRT_IMSIC_S].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE; imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) * @@ -594,18 +595,18 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop(mc->fdt, imsic_name, "interrupts-extended", imsic_cells, mc->smp.cpus * sizeof(uint32_t) * 2); qemu_fdt_setprop(mc->fdt, imsic_name, "reg", imsic_regs, - riscv_socket_count(mc) * sizeof(uint32_t) * 4); + socket_count * sizeof(uint32_t) * 4); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); if (imsic_guest_bits) { qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,guest-index-bits", imsic_guest_bits); } - if (riscv_socket_count(mc) > 1) { + if (socket_count > 1) { qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits", imsic_num_bits(imsic_max_hart_per_socket)); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-bits", - imsic_num_bits(riscv_socket_count(mc))); + imsic_num_bits(socket_count)); qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-shift", IMSIC_MMIO_GROUP_MIN_SHIFT); } @@ -733,6 +734,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, MachineState *mc = MACHINE(s); uint32_t msi_m_phandle = 0, msi_s_phandle = 0; uint32_t *intc_phandles, xplic_phandles[MAX_NODES]; + int socket_count = riscv_socket_count(mc); qemu_fdt_add_subnode(mc->fdt, "/cpus"); qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency", @@ -744,7 +746,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, intc_phandles = g_new0(uint32_t, mc->smp.cpus); phandle_pos = mc->smp.cpus; - for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) { + for (socket = (socket_count - 1); socket >= 0; socket--) { phandle_pos -= s->soc[socket].num_harts; clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); @@ -775,7 +777,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, } phandle_pos = mc->smp.cpus; - for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) { + for (socket = (socket_count - 1); socket >= 0; socket--) { phandle_pos -= s->soc[socket].num_harts; if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -790,7 +792,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, g_free(intc_phandles); - for (socket = 0; socket < riscv_socket_count(mc); socket++) { + for (socket = 0; socket < socket_count; socket++) { if (socket == 0) { *irq_mmio_phandle = xplic_phandles[socket]; *irq_virtio_phandle = xplic_phandles[socket]; @@ -1051,7 +1053,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) /* Pass seed to RNG */ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); - qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", + rng_seed, sizeof(rng_seed)); } static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, @@ -1328,9 +1331,10 @@ static void virt_machine_init(MachineState *machine) char *soc_name; DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip; int i, base_hartid, hart_count; + int socket_count = riscv_socket_count(machine); /* Check socket count limit */ - if (VIRT_SOCKETS_MAX < riscv_socket_count(machine)) { + if (VIRT_SOCKETS_MAX < socket_count) { error_report("number of sockets/nodes should be less than %d", VIRT_SOCKETS_MAX); exit(1); @@ -1338,7 +1342,7 @@ static void virt_machine_init(MachineState *machine) /* Initialize sockets */ mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL; - for (i = 0; i < riscv_socket_count(machine); i++) { + for (i = 0; i < socket_count; i++) { if (!riscv_socket_check_hartids(machine, i)) { error_report("discontinuous hartids in socket%d", i); exit(1); From 568e0614d0979e0431a8d9dc0503a63b8b0f2d81 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 24 Jan 2023 18:22:33 -0300 Subject: [PATCH 577/814] hw/riscv/virt.c: rename MachineState 'mc' pointers to 'ms' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have a convention in other QEMU boards/archs to name MachineState pointers as either 'machine' or 'ms'. MachineClass pointers are usually called 'mc'. The 'virt' RISC-V machine has a lot of instances where MachineState pointers are named 'mc'. There is nothing wrong with that, but we gain more compatibility with the rest of the QEMU code base, and easier reviews, if we follow QEMU conventions. Rename all 'mc' MachineState pointers to 'ms'. This is a very tedious and mechanical patch that was produced by doing the following: - find/replace all 'MachineState *mc' to 'MachineState *ms'; - find/replace all 'mc->fdt' to 'ms->fdt'; - find/replace all 'mc->smp.cpus' to 'ms->smp.cpus'; - replace any remaining occurrences of 'mc' that the compiler complained about. Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Signed-off-by: Daniel Henrique Barboza Message-Id: <20230124212234.412630-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 434 ++++++++++++++++++++++++------------------------ 1 file changed, 217 insertions(+), 217 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 61fdb52090..e420254de2 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -227,7 +227,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, { int cpu; uint32_t cpu_phandle; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); char *name, *cpu_name, *core_name, *intc_name; bool is_32_bit = riscv_is_32bit(&s->soc[0]); @@ -236,40 +236,40 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); - qemu_fdt_add_subnode(mc->fdt, cpu_name); + qemu_fdt_add_subnode(ms->fdt, cpu_name); if (riscv_feature(&s->soc[socket].harts[cpu].env, RISCV_FEATURE_MMU)) { - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", + qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); } else { - qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", + qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", "riscv,none"); } name = riscv_isa_string(&s->soc[socket].harts[cpu]); - qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); + qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name); g_free(name); - qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv"); - qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay"); - qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg", + qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv"); + qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay"); + qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg", s->soc[socket].hartid_base + cpu); - qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu"); - riscv_socket_fdt_write_id(mc, cpu_name, socket); - qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle); + qemu_fdt_setprop_string(ms->fdt, cpu_name, "device_type", "cpu"); + riscv_socket_fdt_write_id(ms, cpu_name, socket); + qemu_fdt_setprop_cell(ms->fdt, cpu_name, "phandle", cpu_phandle); intc_phandles[cpu] = (*phandle)++; intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name); - qemu_fdt_add_subnode(mc->fdt, intc_name); - qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle", + qemu_fdt_add_subnode(ms->fdt, intc_name); + qemu_fdt_setprop_cell(ms->fdt, intc_name, "phandle", intc_phandles[cpu]); - qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible", + qemu_fdt_setprop_string(ms->fdt, intc_name, "compatible", "riscv,cpu-intc"); - qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1); + qemu_fdt_setprop(ms->fdt, intc_name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, intc_name, "#interrupt-cells", 1); core_name = g_strdup_printf("%s/core%d", clust_name, cpu); - qemu_fdt_add_subnode(mc->fdt, core_name); - qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle); + qemu_fdt_add_subnode(ms->fdt, core_name); + qemu_fdt_setprop_cell(ms->fdt, core_name, "cpu", cpu_phandle); g_free(core_name); g_free(intc_name); @@ -282,16 +282,16 @@ static void create_fdt_socket_memory(RISCVVirtState *s, { char *mem_name; uint64_t addr, size; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); - addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket); - size = riscv_socket_mem_size(mc, socket); + addr = 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(mc->fdt, mem_name); - qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg", + qemu_fdt_add_subnode(ms->fdt, mem_name); + qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); - qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory"); - riscv_socket_fdt_write_id(mc, mem_name, socket); + qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory"); + riscv_socket_fdt_write_id(ms, mem_name, socket); g_free(mem_name); } @@ -303,7 +303,7 @@ static void create_fdt_socket_clint(RISCVVirtState *s, char *clint_name; uint32_t *clint_cells; unsigned long clint_addr; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); static const char * const clint_compat[2] = { "sifive,clint0", "riscv,clint0" }; @@ -319,15 +319,15 @@ static void create_fdt_socket_clint(RISCVVirtState *s, clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); - qemu_fdt_add_subnode(mc->fdt, clint_name); - qemu_fdt_setprop_string_array(mc->fdt, clint_name, "compatible", + 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(mc->fdt, clint_name, "reg", + qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg", 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); - qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended", + 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(mc, clint_name, socket); + riscv_socket_fdt_write_id(ms, clint_name, socket); g_free(clint_name); g_free(clint_cells); @@ -344,7 +344,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, uint32_t *aclint_mswi_cells; uint32_t *aclint_sswi_cells; uint32_t *aclint_mtimer_cells; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); @@ -363,16 +363,16 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); name = g_strdup_printf("/soc/mswi@%lx", addr); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mswi"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE); - qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_mswi_cells, aclint_cells_size); - qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); - riscv_socket_fdt_write_id(mc, name, socket); + qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0); + riscv_socket_fdt_write_id(ms, name, socket); g_free(name); } @@ -386,33 +386,33 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, size = memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; } name = g_strdup_printf("/soc/mtimer@%lx", addr); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mtimer"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, addr + RISCV_ACLINT_DEFAULT_MTIME, 0x0, size - RISCV_ACLINT_DEFAULT_MTIME, 0x0, addr + RISCV_ACLINT_DEFAULT_MTIMECMP, 0x0, RISCV_ACLINT_DEFAULT_MTIME); - qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_mtimer_cells, aclint_cells_size); - riscv_socket_fdt_write_id(mc, name, socket); + riscv_socket_fdt_write_id(ms, name, socket); g_free(name); if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { addr = memmap[VIRT_ACLINT_SSWI].base + (memmap[VIRT_ACLINT_SSWI].size * socket); name = g_strdup_printf("/soc/sswi@%lx", addr); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-sswi"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size); - qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_sswi_cells, aclint_cells_size); - qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); - riscv_socket_fdt_write_id(mc, name, socket); + qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0); + riscv_socket_fdt_write_id(ms, name, socket); g_free(name); } @@ -430,7 +430,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s, char *plic_name; uint32_t *plic_cells; unsigned long plic_addr; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); static const char * const plic_compat[2] = { "sifive,plic-1.0.0", "riscv,plic0" }; @@ -456,27 +456,27 @@ static void create_fdt_socket_plic(RISCVVirtState *s, plic_phandles[socket] = (*phandle)++; plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); - qemu_fdt_add_subnode(mc->fdt, plic_name); - qemu_fdt_setprop_cell(mc->fdt, plic_name, + qemu_fdt_add_subnode(ms->fdt, plic_name); + qemu_fdt_setprop_cell(ms->fdt, plic_name, "#interrupt-cells", FDT_PLIC_INT_CELLS); - qemu_fdt_setprop_cell(mc->fdt, plic_name, + qemu_fdt_setprop_cell(ms->fdt, plic_name, "#address-cells", FDT_PLIC_ADDR_CELLS); - qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible", + qemu_fdt_setprop_string_array(ms->fdt, plic_name, "compatible", (char **)&plic_compat, ARRAY_SIZE(plic_compat)); - qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); - qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg", + qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); - qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", + qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", VIRT_IRQCHIP_NUM_SOURCES - 1); - riscv_socket_fdt_write_id(mc, plic_name, socket); - qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle", + riscv_socket_fdt_write_id(ms, plic_name, socket); + qemu_fdt_setprop_cell(ms->fdt, plic_name, "phandle", plic_phandles[socket]); if (!socket) { - platform_bus_add_all_fdt_nodes(mc->fdt, plic_name, + platform_bus_add_all_fdt_nodes(ms->fdt, plic_name, memmap[VIRT_PLATFORM_BUS].base, memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); @@ -504,18 +504,18 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, { int cpu, socket; char *imsic_name; - MachineState *mc = MACHINE(s); - int socket_count = riscv_socket_count(mc); + MachineState *ms = MACHINE(s); + int socket_count = riscv_socket_count(ms); uint32_t imsic_max_hart_per_socket, imsic_guest_bits; uint32_t *imsic_cells, *imsic_regs, imsic_addr, imsic_size; *msi_m_phandle = (*phandle)++; *msi_s_phandle = (*phandle)++; - imsic_cells = g_new0(uint32_t, mc->smp.cpus * 2); + imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2); imsic_regs = g_new0(uint32_t, socket_count * 4); /* M-level IMSIC node */ - for (cpu = 0; cpu < mc->smp.cpus; cpu++) { + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT); } @@ -534,35 +534,35 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, } imsic_name = g_strdup_printf("/soc/imsics@%lx", (unsigned long)memmap[VIRT_IMSIC_M].base); - qemu_fdt_add_subnode(mc->fdt, imsic_name); - qemu_fdt_setprop_string(mc->fdt, imsic_name, "compatible", + qemu_fdt_add_subnode(ms->fdt, imsic_name); + qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", "riscv,imsics"); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "#interrupt-cells", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells", FDT_IMSIC_INT_CELLS); - qemu_fdt_setprop(mc->fdt, imsic_name, "interrupt-controller", + qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop(mc->fdt, imsic_name, "msi-controller", + qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0); - qemu_fdt_setprop(mc->fdt, imsic_name, "interrupts-extended", - imsic_cells, mc->smp.cpus * sizeof(uint32_t) * 2); - qemu_fdt_setprop(mc->fdt, imsic_name, "reg", imsic_regs, + qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended", + imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2); + qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs, socket_count * sizeof(uint32_t) * 4); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); if (socket_count > 1) { - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits", imsic_num_bits(imsic_max_hart_per_socket)); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-bits", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits", imsic_num_bits(socket_count)); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-shift", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift", IMSIC_MMIO_GROUP_MIN_SHIFT); } - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "phandle", *msi_m_phandle); + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_m_phandle); g_free(imsic_name); /* S-level IMSIC node */ - for (cpu = 0; cpu < mc->smp.cpus; cpu++) { + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); } @@ -583,34 +583,34 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, } imsic_name = g_strdup_printf("/soc/imsics@%lx", (unsigned long)memmap[VIRT_IMSIC_S].base); - qemu_fdt_add_subnode(mc->fdt, imsic_name); - qemu_fdt_setprop_string(mc->fdt, imsic_name, "compatible", + qemu_fdt_add_subnode(ms->fdt, imsic_name); + qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", "riscv,imsics"); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "#interrupt-cells", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells", FDT_IMSIC_INT_CELLS); - qemu_fdt_setprop(mc->fdt, imsic_name, "interrupt-controller", + qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop(mc->fdt, imsic_name, "msi-controller", + qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0); - qemu_fdt_setprop(mc->fdt, imsic_name, "interrupts-extended", - imsic_cells, mc->smp.cpus * sizeof(uint32_t) * 2); - qemu_fdt_setprop(mc->fdt, imsic_name, "reg", imsic_regs, + qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended", + imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2); + qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs, socket_count * sizeof(uint32_t) * 4); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids", VIRT_IRQCHIP_NUM_MSIS); if (imsic_guest_bits) { - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,guest-index-bits", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,guest-index-bits", imsic_guest_bits); } if (socket_count > 1) { - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits", imsic_num_bits(imsic_max_hart_per_socket)); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-bits", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits", imsic_num_bits(socket_count)); - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,group-index-shift", + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift", IMSIC_MMIO_GROUP_MIN_SHIFT); } - qemu_fdt_setprop_cell(mc->fdt, imsic_name, "phandle", *msi_s_phandle); + qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_s_phandle); g_free(imsic_name); g_free(imsic_regs); @@ -629,7 +629,7 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, char *aplic_name; uint32_t *aplic_cells; unsigned long aplic_addr; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); uint32_t aplic_m_phandle, aplic_s_phandle; aplic_m_phandle = (*phandle)++; @@ -644,28 +644,28 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, aplic_addr = memmap[VIRT_APLIC_M].base + (memmap[VIRT_APLIC_M].size * socket); aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr); - qemu_fdt_add_subnode(mc->fdt, aplic_name); - qemu_fdt_setprop_string(mc->fdt, aplic_name, "compatible", "riscv,aplic"); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, + qemu_fdt_add_subnode(ms->fdt, aplic_name); + qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic"); + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#interrupt-cells", FDT_APLIC_INT_CELLS); - qemu_fdt_setprop(mc->fdt, aplic_name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0); if (s->aia_type == VIRT_AIA_TYPE_APLIC) { - qemu_fdt_setprop(mc->fdt, aplic_name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended", aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2); } else { - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "msi-parent", + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_m_phandle); } - qemu_fdt_setprop_cells(mc->fdt, aplic_name, "reg", + qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg", 0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_M].size); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,num-sources", + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources", VIRT_IRQCHIP_NUM_SOURCES); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,children", + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children", aplic_s_phandle); - qemu_fdt_setprop_cells(mc->fdt, aplic_name, "riscv,delegate", + qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate", aplic_s_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES); - riscv_socket_fdt_write_id(mc, aplic_name, socket); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_m_phandle); + riscv_socket_fdt_write_id(ms, aplic_name, socket); + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_m_phandle); g_free(aplic_name); /* S-level APLIC node */ @@ -676,27 +676,27 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, aplic_addr = memmap[VIRT_APLIC_S].base + (memmap[VIRT_APLIC_S].size * socket); aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr); - qemu_fdt_add_subnode(mc->fdt, aplic_name); - qemu_fdt_setprop_string(mc->fdt, aplic_name, "compatible", "riscv,aplic"); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, + qemu_fdt_add_subnode(ms->fdt, aplic_name); + qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic"); + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#interrupt-cells", FDT_APLIC_INT_CELLS); - qemu_fdt_setprop(mc->fdt, aplic_name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0); if (s->aia_type == VIRT_AIA_TYPE_APLIC) { - qemu_fdt_setprop(mc->fdt, aplic_name, "interrupts-extended", + qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended", aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2); } else { - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "msi-parent", + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_s_phandle); } - qemu_fdt_setprop_cells(mc->fdt, aplic_name, "reg", + qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg", 0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_S].size); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,num-sources", + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources", VIRT_IRQCHIP_NUM_SOURCES); - riscv_socket_fdt_write_id(mc, aplic_name, socket); - qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_s_phandle); + riscv_socket_fdt_write_id(ms, aplic_name, socket); + qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_s_phandle); if (!socket) { - platform_bus_add_all_fdt_nodes(mc->fdt, aplic_name, + platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name, memmap[VIRT_PLATFORM_BUS].base, memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); @@ -711,13 +711,13 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, static void create_fdt_pmu(RISCVVirtState *s) { char *pmu_name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); RISCVCPU hart = s->soc[0].harts[0]; pmu_name = g_strdup_printf("/soc/pmu"); - qemu_fdt_add_subnode(mc->fdt, pmu_name); - qemu_fdt_setprop_string(mc->fdt, pmu_name, "compatible", "riscv,pmu"); - riscv_pmu_generate_fdt_node(mc->fdt, hart.cfg.pmu_num, pmu_name); + qemu_fdt_add_subnode(ms->fdt, pmu_name); + qemu_fdt_setprop_string(ms->fdt, pmu_name, "compatible", "riscv,pmu"); + riscv_pmu_generate_fdt_node(ms->fdt, hart.cfg.pmu_num, pmu_name); g_free(pmu_name); } @@ -731,26 +731,26 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, { char *clust_name; int socket, phandle_pos; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); uint32_t msi_m_phandle = 0, msi_s_phandle = 0; uint32_t *intc_phandles, xplic_phandles[MAX_NODES]; - int socket_count = riscv_socket_count(mc); + int socket_count = riscv_socket_count(ms); - qemu_fdt_add_subnode(mc->fdt, "/cpus"); - qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency", + qemu_fdt_add_subnode(ms->fdt, "/cpus"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency", RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ); - qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0); - qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1); - qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); + qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); - intc_phandles = g_new0(uint32_t, mc->smp.cpus); + intc_phandles = g_new0(uint32_t, ms->smp.cpus); - phandle_pos = mc->smp.cpus; + phandle_pos = ms->smp.cpus; for (socket = (socket_count - 1); socket >= 0; socket--) { phandle_pos -= s->soc[socket].num_harts; clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); - qemu_fdt_add_subnode(mc->fdt, clust_name); + qemu_fdt_add_subnode(ms->fdt, clust_name); create_fdt_socket_cpus(s, socket, clust_name, phandle, &intc_phandles[phandle_pos]); @@ -776,7 +776,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, *msi_pcie_phandle = msi_s_phandle; } - phandle_pos = mc->smp.cpus; + phandle_pos = ms->smp.cpus; for (socket = (socket_count - 1); socket >= 0; socket--) { phandle_pos -= s->soc[socket].num_harts; @@ -807,7 +807,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, } } - riscv_socket_fdt_write_distance_matrix(mc); + riscv_socket_fdt_write_distance_matrix(ms); } static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, @@ -815,23 +815,23 @@ static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, { int i; char *name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); for (i = 0; i < VIRTIO_COUNT; i++) { name = g_strdup_printf("/soc/virtio_mmio@%lx", (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + 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); - qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", + qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_virtio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { - qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", + qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", VIRTIO_IRQ + i); } else { - qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", VIRTIO_IRQ + i, 0x4); } g_free(name); @@ -843,29 +843,29 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t msi_pcie_phandle) { char *name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/pci@%lx", (long) memmap[VIRT_PCIE_ECAM].base); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS); - qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", + qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", FDT_PCI_INT_CELLS); - qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", + qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "pci-host-ecam-generic"); - qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci"); - qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0); - qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0, + 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); - qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0); + qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0); if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - qemu_fdt_setprop_cell(mc->fdt, name, "msi-parent", msi_pcie_phandle); + qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle); } - qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0, + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0, memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size); - qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges", + 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, 1, FDT_PCI_RANGE_MMIO, @@ -875,7 +875,7 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); - create_pcie_irq_map(s, mc->fdt, name, irq_pcie_phandle); + create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); g_free(name); } @@ -884,39 +884,39 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, { char *name; uint32_t test_phandle; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); test_phandle = (*phandle)++; name = g_strdup_printf("/soc/test@%lx", (long)memmap[VIRT_TEST].base); - qemu_fdt_add_subnode(mc->fdt, name); + qemu_fdt_add_subnode(ms->fdt, name); { static const char * const compat[3] = { "sifive,test1", "sifive,test0", "syscon" }; - qemu_fdt_setprop_string_array(mc->fdt, name, "compatible", + qemu_fdt_setprop_string_array(ms->fdt, name, "compatible", (char **)&compat, ARRAY_SIZE(compat)); } - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size); - qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle); - test_phandle = qemu_fdt_get_phandle(mc->fdt, name); + qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle); + test_phandle = qemu_fdt_get_phandle(ms->fdt, name); g_free(name); name = g_strdup_printf("/reboot"); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot"); - qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); - qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0); - qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET); + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); + qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle); + qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0); + qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_RESET); g_free(name); name = g_strdup_printf("/poweroff"); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff"); - qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); - qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0); - qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS); + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); + qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle); + qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0); + qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_PASS); g_free(name); } @@ -924,24 +924,24 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_mmio_phandle) { char *name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + 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); - qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400); - qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle); + 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) { - qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ); + qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", UART0_IRQ); } else { - qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", UART0_IRQ, 0x4); + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", UART0_IRQ, 0x4); } - qemu_fdt_add_subnode(mc->fdt, "/chosen"); - qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name); + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); g_free(name); } @@ -949,20 +949,20 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_mmio_phandle) { char *name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); - qemu_fdt_setprop_cells(mc->fdt, name, "reg", + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); - qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", + qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { - qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ); + qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ); } else { - qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", RTC_IRQ, 0x4); + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4); } g_free(name); } @@ -970,68 +970,68 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) { char *name; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; hwaddr flashbase = virt_memmap[VIRT_FLASH].base; name = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(mc->fdt, name); - qemu_fdt_setprop_string(mc->fdt, name, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(mc->fdt, name, "reg", + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2, flashbase, 2, flashsize, 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4); + qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4); g_free(name); } static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) { char *nodename; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); hwaddr base = memmap[VIRT_FW_CFG].base; hwaddr size = memmap[VIRT_FW_CFG].size; nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(mc->fdt, nodename); - qemu_fdt_setprop_string(mc->fdt, nodename, + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); g_free(nodename); } static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) { - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint8_t rng_seed[32]; - if (mc->dtb) { - mc->fdt = load_device_tree(mc->dtb, &s->fdt_size); - if (!mc->fdt) { + if (ms->dtb) { + ms->fdt = load_device_tree(ms->dtb, &s->fdt_size); + if (!ms->fdt) { error_report("load_device_tree() failed"); exit(1); } } else { - mc->fdt = create_device_tree(&s->fdt_size); - if (!mc->fdt) { + ms->fdt = create_device_tree(&s->fdt_size); + if (!ms->fdt) { error_report("create_device_tree() failed"); exit(1); } } - qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu"); - qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio"); - qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2); - qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/", "model", "riscv-virtio,qemu"); + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "riscv-virtio"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); - qemu_fdt_add_subnode(mc->fdt, "/soc"); - qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0); - qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus"); - qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2); - qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_add_subnode(ms->fdt, "/soc"); + qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); create_fdt_sockets(s, memmap, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, @@ -1053,7 +1053,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) /* Pass seed to RNG */ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); - qemu_fdt_setprop(mc->fdt, "/chosen", "rng-seed", + qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); } @@ -1106,14 +1106,14 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, return dev; } -static FWCfgState *create_fw_cfg(const MachineState *mc) +static FWCfgState *create_fw_cfg(const MachineState *ms) { hwaddr base = virt_memmap[VIRT_FW_CFG].base; FWCfgState *fw_cfg; fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, &address_space_memory); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)mc->smp.cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus); return fw_cfg; } From 606a2439babb7d676af32e15232e94159d67bbeb Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 24 Jan 2023 18:22:34 -0300 Subject: [PATCH 578/814] hw/riscv/spike.c: rename MachineState 'mc' pointers to' ms' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the QEMU convention of naming MachineState pointers as 'ms' by renaming the instances where we're calling it 'mc'. Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Signed-off-by: Daniel Henrique Barboza Message-Id: <20230124212234.412630-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/spike.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index badc11ec43..04d236296b 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -56,7 +56,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, uint64_t addr, size; unsigned long clint_addr; int cpu, socket; - MachineState *mc = MACHINE(s); + MachineState *ms = MACHINE(s); uint32_t *clint_cells; uint32_t cpu_phandle, intc_phandle, phandle = 1; char *name, *mem_name, *clint_name, *clust_name; @@ -65,7 +65,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, "sifive,clint0", "riscv,clint0" }; - fdt = mc->fdt = create_device_tree(&fdt_size); + fdt = ms->fdt = create_device_tree(&fdt_size); if (!fdt) { error_report("create_device_tree() failed"); exit(1); @@ -96,7 +96,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); qemu_fdt_add_subnode(fdt, "/cpus/cpu-map"); - for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) { + for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket--) { clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); qemu_fdt_add_subnode(fdt, clust_name); @@ -121,7 +121,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cell(fdt, cpu_name, "reg", s->soc[socket].hartid_base + cpu); qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); - riscv_socket_fdt_write_id(mc, cpu_name, socket); + riscv_socket_fdt_write_id(ms, cpu_name, socket); qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle); intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name); @@ -147,14 +147,14 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, g_free(cpu_name); } - addr = memmap[SPIKE_DRAM].base + riscv_socket_mem_offset(mc, socket); - size = riscv_socket_mem_size(mc, socket); + addr = memmap[SPIKE_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(fdt, mem_name); qemu_fdt_setprop_cells(fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory"); - riscv_socket_fdt_write_id(mc, mem_name, socket); + riscv_socket_fdt_write_id(ms, mem_name, socket); g_free(mem_name); clint_addr = memmap[SPIKE_CLINT].base + @@ -167,14 +167,14 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, 0x0, clint_addr, 0x0, memmap[SPIKE_CLINT].size); qemu_fdt_setprop(fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); - riscv_socket_fdt_write_id(mc, clint_name, socket); + riscv_socket_fdt_write_id(ms, clint_name, socket); g_free(clint_name); g_free(clint_cells); g_free(clust_name); } - riscv_socket_fdt_write_distance_matrix(mc); + riscv_socket_fdt_write_distance_matrix(ms); qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif"); From 26934f9a95264221ed8e6d603b8099508fbd2a5e Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Tue, 31 Jan 2023 20:09:55 +0300 Subject: [PATCH 579/814] target/riscv: set tval for triggered watchpoints According to privileged spec, if [sm]tval is written with a nonzero value when a breakpoint exception occurs, then [sm]tval will contain the faulting virtual address. Set tval to hit address when breakpoint exception is triggered by hardware watchpoint. Signed-off-by: Sergey Matyukevich Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20230131170955.752743-1-geomatsi@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 6 ++++++ target/riscv/debug.c | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 0d72466f3b..ad8d82662c 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1639,6 +1639,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) case RISCV_EXCP_VIRT_INSTRUCTION_FAULT: tval = env->bins; break; + case RISCV_EXCP_BREAKPOINT: + if (cs->watchpoint_hit) { + tval = cs->watchpoint_hit->hitaddr; + cs->watchpoint_hit = NULL; + } + break; default: break; } diff --git a/target/riscv/debug.c b/target/riscv/debug.c index bf4840a6a3..b091293069 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -761,7 +761,6 @@ void riscv_cpu_debug_excp_handler(CPUState *cs) if (cs->watchpoint_hit) { if (cs->watchpoint_hit->flags & BP_CPU) { - cs->watchpoint_hit = NULL; do_trigger_action(env, DBG_ACTION_BP); } } else { From 909f7da60472b82668d2b2abdb19eba53603b408 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 1 Feb 2023 14:12:10 -0300 Subject: [PATCH 580/814] hw/riscv/boot.c: calculate fdt size after fdt_pack() fdt_pack() can change the fdt size, meaning that fdt_totalsize() can contain a now deprecated (bigger) value. Reviewed-by: Alistair Francis Signed-off-by: Daniel Henrique Barboza Message-Id: <20230201171212.1219375-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index cb27798a25..2d03a9a921 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -253,8 +253,13 @@ uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) { uint64_t temp, fdt_addr; hwaddr dram_end = dram_base + mem_size; - int ret, fdtsize = fdt_totalsize(fdt); + int ret = fdt_pack(fdt); + int fdtsize; + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); + + fdtsize = fdt_totalsize(fdt); if (fdtsize <= 0) { error_report("invalid device-tree"); exit(1); @@ -269,9 +274,6 @@ uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); - ret = fdt_pack(fdt); - /* Should only fail if we've built a corrupted tree */ - g_assert(ret == 0); /* copy in the device tree */ qemu_fdt_dumpdtb(fdt, fdtsize); From bc2c01535317ebfd994668bb04a040c452247be3 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 1 Feb 2023 14:12:11 -0300 Subject: [PATCH 581/814] hw/riscv: split fdt address calculation from fdt load A common trend in other archs is to calculate the fdt address, which is usually straightforward, and then calling a function that loads the fdt/dtb by using that address. riscv_load_fdt() is doing a bit too much in comparison. It's calculating the fdt address via an elaborated heuristic to put the FDT at the bottom of DRAM, and "bottom of DRAM" will vary across boards and configurations, then it's actually loading the fdt, and finally it's returning the fdt address used to the caller. Reduce the existing complexity of riscv_load_fdt() by splitting its code into a new function, riscv_compute_fdt_addr(), that will take care of all fdt address logic. riscv_load_fdt() can then be a simple function that just loads a fdt at the given fdt address. We're also taken the opportunity to clarify the intentions and assumptions made by these functions. riscv_load_fdt() is now receiving a hwaddr as fdt_addr because there is no restriction of having to load the fdt in higher addresses that doesn't fit in an uint32_t. Reviewed-by: Alistair Francis Signed-off-by: Daniel Henrique Barboza Message-Id: <20230201171212.1219375-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 30 +++++++++++++++++++++++++----- hw/riscv/microchip_pfsoc.c | 6 ++++-- hw/riscv/sifive_u.c | 7 ++++--- hw/riscv/spike.c | 6 +++--- hw/riscv/virt.c | 7 ++++--- include/hw/riscv/boot.h | 4 +++- 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 2d03a9a921..2e53494b08 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -249,9 +249,21 @@ void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) } } -uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) +/* + * The FDT should be put at the farthest point possible to + * avoid overwriting it with the kernel/initrd. + * + * This function makes an assumption that the DRAM is + * contiguous. It also cares about 32-bit systems and + * will limit fdt_addr to be addressable by them even for + * 64-bit CPUs. + * + * The FDT is fdt_packed() during the calculation. + */ +uint64_t riscv_compute_fdt_addr(hwaddr dram_base, uint64_t mem_size, + void *fdt) { - uint64_t temp, fdt_addr; + uint64_t temp; hwaddr dram_end = dram_base + mem_size; int ret = fdt_pack(fdt); int fdtsize; @@ -272,7 +284,17 @@ uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) * end of dram or 3GB whichever is lesser. */ temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; - fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); + + return QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); +} + +/* + * 'fdt_addr' is received as hwaddr because boards might put + * the FDT beyond 32-bit addressing boundary. + */ +void riscv_load_fdt(hwaddr fdt_addr, void *fdt) +{ + uint32_t fdtsize = fdt_totalsize(fdt); /* copy in the device tree */ qemu_fdt_dumpdtb(fdt, fdtsize); @@ -281,8 +303,6 @@ uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt) &address_space_memory); qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize)); - - return fdt_addr; } void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base, diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 82ae5e7023..17499d4152 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -641,8 +641,10 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_load_fdt(memmap[MICROCHIP_PFSOC_DRAM_LO].base, - machine->ram_size, machine->fdt); + fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, + machine->ram_size, machine->fdt); + 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, diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 2fb6ee231f..626d4dc2f3 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -616,9 +616,10 @@ static void sifive_u_machine_init(MachineState *machine) kernel_entry = 0; } - /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DEV_DRAM].base, - machine->ram_size, machine->fdt); + fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base, + machine->ram_size, machine->fdt); + riscv_load_fdt(fdt_load_addr, machine->fdt); + if (!riscv_is_32bit(&s->soc.u_cpus)) { start_addr_hi32 = (uint64_t)start_addr >> 32; } diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 04d236296b..f1114f2c71 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -324,9 +324,9 @@ static void spike_board_init(MachineState *machine) kernel_entry = 0; } - /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, - machine->ram_size, machine->fdt); + fdt_load_addr = riscv_compute_fdt_addr(memmap[SPIKE_DRAM].base, + machine->ram_size, machine->fdt); + riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e420254de2..2e0a0cdb17 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1303,9 +1303,10 @@ static void virt_machine_done(Notifier *notifier, void *data) start_addr = virt_memmap[VIRT_FLASH].base; } - /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base, - machine->ram_size, machine->fdt); + fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, + machine->ram_size, machine->fdt); + 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, diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index f94653a09b..46de4ec46b 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -47,7 +47,9 @@ target_ulong riscv_load_kernel(MachineState *machine, target_ulong firmware_end_addr, symbol_fn_t sym_cb); void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry); -uint64_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt); +uint64_t riscv_compute_fdt_addr(hwaddr dram_start, uint64_t dram_size, + void *fdt); +void riscv_load_fdt(hwaddr fdt_addr, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, hwaddr rom_base, hwaddr rom_size, From 4b402886ac89732f903094004612039d0fd5b4cb Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 1 Feb 2023 14:12:12 -0300 Subject: [PATCH 582/814] hw/riscv: change riscv_compute_fdt_addr() semantics As it is now, riscv_compute_fdt_addr() is receiving a dram_base, a mem_size (which is defaulted to MachineState::ram_size in all boards) and the FDT pointer. And it makes a very important assumption: the DRAM interval dram_base + mem_size is contiguous. This is indeed the case for most boards that use a FDT. The Icicle Kit board works with 2 distinct RAM banks that are separated by a gap. We have a lower bank with 1GiB size, a gap follows, then at 64GiB the high memory starts. MachineClass::default_ram_size for this board is set to 1.5Gb, and machine_init() is enforcing it as minimal RAM size, meaning that there we'll always have at least 512 MiB in the Hi RAM area. Using riscv_compute_fdt_addr() in this board is weird because not only the board has sparse RAM, and it's calling it using the base address of the Lo RAM area, but it's also using a mem_size that we have guarantees that it will go up to the Hi RAM. All the function assumptions doesn't work for this board. In fact, what makes the function works at all in this case is a coincidence. Commit 1a475d39ef54 introduced a 3GB boundary for the FDT, down from 4Gb, that is enforced if dram_base is lower than 3072 MiB. For the Icicle Kit board, memmap[MICROCHIP_PFSOC_DRAM_LO].base is 0x80000000 (2 Gb) and it has a 1Gb size, so it will fall in the conditions to put the FDT under a 3Gb address, which happens to be exactly at the end of DRAM_LO. If the base address of the Lo area started later than 3Gb this function would be unusable by the board. Changing any assumptions inside riscv_compute_fdt_addr() can also break it by accident as well. Let's change riscv_compute_fdt_addr() semantics to be appropriate to the Icicle Kit board and for future boards that might have sparse RAM topologies to worry about: - relieve the condition that the dram_base + mem_size area is contiguous, since this is already not the case today; - receive an extra 'dram_size' size attribute that refers to a contiguous RAM block that the board wants the FDT to reside on. Together with 'mem_size' and 'fdt', which are now now being consumed by a MachineState pointer, we're able to make clear assumptions based on the DRAM block and total mem_size available to ensure that the FDT will be put in a valid RAM address. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-Id: <20230201171212.1219375-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 35 +++++++++++++++++++++++------------ hw/riscv/microchip_pfsoc.c | 3 ++- hw/riscv/sifive_u.c | 3 ++- hw/riscv/spike.c | 3 ++- hw/riscv/virt.c | 3 ++- include/hw/riscv/boot.h | 2 +- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 2e53494b08..c7e0e50bd8 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -250,33 +250,44 @@ void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) } /* - * The FDT should be put at the farthest point possible to - * avoid overwriting it with the kernel/initrd. + * This function makes an assumption that the DRAM interval + * 'dram_base' + 'dram_size' is contiguous. * - * This function makes an assumption that the DRAM is - * contiguous. It also cares about 32-bit systems and - * will limit fdt_addr to be addressable by them even for - * 64-bit CPUs. + * Considering that 'dram_end' is the lowest value between + * the end of the DRAM block and MachineState->ram_size, the + * FDT location will vary according to 'dram_base': + * + * - if 'dram_base' is less that 3072 MiB, the FDT will be + * put at the lowest value between 3072 MiB and 'dram_end'; + * + * - if 'dram_base' is higher than 3072 MiB, the FDT will be + * put at 'dram_end'. * * The FDT is fdt_packed() during the calculation. */ -uint64_t riscv_compute_fdt_addr(hwaddr dram_base, uint64_t mem_size, - void *fdt) +uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, + MachineState *ms) { - uint64_t temp; - hwaddr dram_end = dram_base + mem_size; - int ret = fdt_pack(fdt); + int ret = fdt_pack(ms->fdt); + hwaddr dram_end, temp; int fdtsize; /* Should only fail if we've built a corrupted tree */ g_assert(ret == 0); - fdtsize = fdt_totalsize(fdt); + fdtsize = fdt_totalsize(ms->fdt); if (fdtsize <= 0) { error_report("invalid device-tree"); exit(1); } + /* + * A dram_size == 0, usually from a MemMapEntry[].size element, + * means that the DRAM block goes all the way to ms->ram_size. + */ + dram_end = dram_base; + dram_end += dram_size ? MIN(ms->ram_size, dram_size) : ms->ram_size; + /* * We should put fdt as far as possible to avoid kernel/initrd overwriting * its content. But it should be addressable by 32 bit system as well. diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 17499d4152..2b91e49561 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -642,7 +642,8 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, - machine->ram_size, machine->fdt); + memmap[MICROCHIP_PFSOC_DRAM_LO].size, + machine); riscv_load_fdt(fdt_load_addr, machine->fdt); /* Load the reset vector */ diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 626d4dc2f3..d3ab7a9cda 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -617,7 +617,8 @@ static void sifive_u_machine_init(MachineState *machine) } fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base, - machine->ram_size, machine->fdt); + memmap[SIFIVE_U_DEV_DRAM].size, + machine); riscv_load_fdt(fdt_load_addr, machine->fdt); if (!riscv_is_32bit(&s->soc.u_cpus)) { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index f1114f2c71..cc3f6dac17 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -325,7 +325,8 @@ static void spike_board_init(MachineState *machine) } fdt_load_addr = riscv_compute_fdt_addr(memmap[SPIKE_DRAM].base, - machine->ram_size, machine->fdt); + memmap[SPIKE_DRAM].size, + machine); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2e0a0cdb17..a061151a6f 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1304,7 +1304,8 @@ static void virt_machine_done(Notifier *notifier, void *data) } fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, - machine->ram_size, machine->fdt); + memmap[VIRT_DRAM].size, + machine); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 46de4ec46b..511390f60e 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -48,7 +48,7 @@ target_ulong riscv_load_kernel(MachineState *machine, symbol_fn_t sym_cb); void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry); uint64_t riscv_compute_fdt_addr(hwaddr dram_start, uint64_t dram_size, - void *fdt); + MachineState *ms); void riscv_load_fdt(hwaddr fdt_addr, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, From 49a7f3aabba99e06768cbaf6c9429f514a9c7444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:00 +0100 Subject: [PATCH 583/814] RISC-V: Adding XTheadCmo ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadCmo ISA extension. To avoid interfering with standard extensions, decoder and translation are in its own xthead* specific files. Future patches should be able to easily add additional T-Head extension. The implementation does not have much functionality (besides accepting the instructions and not qualifying them as illegal instructions if the hart executes in the required privilege level for the instruction), as QEMU does not model CPU caches and instructions are documented to not raise any exceptions. Co-developed-by: LIU Zhiwei Signed-off-by: Christoph Müllner Reviewed-by: Alistair Francis Message-Id: <20230131202013.2541053-2-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 81 ++++++++++++++++++++++ target/riscv/meson.build | 1 + target/riscv/translate.c | 8 +++ target/riscv/xthead.decode | 38 ++++++++++ 6 files changed, 131 insertions(+) create mode 100644 target/riscv/insn_trans/trans_xthead.c.inc create mode 100644 target/riscv/xthead.decode diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 14a7027095..6ea61e5b22 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -109,6 +109,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval), ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), + ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; @@ -1088,6 +1089,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false), /* Vendor-specific custom extensions */ + DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), /* These are experimental so mark with 'x-' */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index bcf0826753..d3ebc6f112 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -473,6 +473,7 @@ struct RISCVCPUConfig { uint64_t mimpid; /* Vendor-specific custom extensions */ + bool ext_xtheadcmo; bool ext_XVentanaCondOps; uint8_t pmu_num; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc new file mode 100644 index 0000000000..24acaf188c --- /dev/null +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -0,0 +1,81 @@ +/* + * RISC-V translation routines for the T-Head vendor extensions (xthead*). + * + * Copyright (c) 2022 VRULL GmbH. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#define REQUIRE_XTHEADCMO(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadcmo) { \ + return false; \ + } \ +} while (0) + +/* XTheadCmo */ + +static inline int priv_level(DisasContext *ctx) +{ +#ifdef CONFIG_USER_ONLY + return PRV_U; +#else + /* Priv level is part of mem_idx. */ + return ctx->mem_idx & TB_FLAGS_PRIV_MMU_MASK; +#endif +} + +/* Test if priv level is M, S, or U (cannot fail). */ +#define REQUIRE_PRIV_MSU(ctx) + +/* Test if priv level is M or S. */ +#define REQUIRE_PRIV_MS(ctx) \ +do { \ + int priv = priv_level(ctx); \ + if (!(priv == PRV_M || \ + priv == PRV_S)) { \ + return false; \ + } \ +} while (0) + +#define NOP_PRIVCHECK(insn, extcheck, privcheck) \ +static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn * a) \ +{ \ + (void) a; \ + extcheck(ctx); \ + privcheck(ctx); \ + return true; \ +} + +NOP_PRIVCHECK(th_dcache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cpa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) +NOP_PRIVCHECK(th_dcache_civa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) +NOP_PRIVCHECK(th_dcache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) +NOP_PRIVCHECK(th_dcache_csw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cisw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_isw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cpal1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) + +NOP_PRIVCHECK(th_icache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_icache_ialls, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_icache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_icache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) + +NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) diff --git a/target/riscv/meson.build b/target/riscv/meson.build index ba25164d74..5dee37a242 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -2,6 +2,7 @@ gen = [ decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']), decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), + decodetree.process('xthead.decode', extra_args: '--static-decode=decode_xthead'), decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'), ] diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 01cc30a365..1e29ac9886 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -130,6 +130,11 @@ static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) return true; } +static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) +{ + return ctx->cfg_ptr->ext_xtheadcmo; +} + #define MATERIALISE_EXT_PREDICATE(ext) \ static bool has_ ## ext ## _p(DisasContext *ctx) \ { \ @@ -1080,6 +1085,8 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvk.c.inc" #include "insn_trans/trans_privileged.c.inc" #include "insn_trans/trans_svinval.c.inc" +#include "decode-xthead.c.inc" +#include "insn_trans/trans_xthead.c.inc" #include "insn_trans/trans_xventanacondops.c.inc" /* Include the auto-generated decoder for 16 bit insn */ @@ -1106,6 +1113,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) bool (*decode_func)(DisasContext *, uint32_t); } decoders[] = { { always_true_p, decode_insn32 }, + { has_xthead_p, decode_xthead }, { has_XVentanaCondOps_p, decode_XVentanaCodeOps }, }; diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode new file mode 100644 index 0000000000..30533a66f5 --- /dev/null +++ b/target/riscv/xthead.decode @@ -0,0 +1,38 @@ +# +# Translation routines for the instructions of the XThead* ISA extensions +# +# Copyright (c) 2022 Christoph Muellner, christoph.muellner@vrull.eu +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# The documentation of the ISA extensions can be found here: +# https://github.com/T-head-Semi/thead-extension-spec/releases/latest + +# Fields: +%rs1 15:5 + +# Formats +@sfence_vm ....... ..... ..... ... ..... ....... %rs1 + +# XTheadCmo +th_dcache_call 0000000 00001 00000 000 00000 0001011 +th_dcache_ciall 0000000 00011 00000 000 00000 0001011 +th_dcache_iall 0000000 00010 00000 000 00000 0001011 +th_dcache_cpa 0000001 01001 ..... 000 00000 0001011 @sfence_vm +th_dcache_cipa 0000001 01011 ..... 000 00000 0001011 @sfence_vm +th_dcache_ipa 0000001 01010 ..... 000 00000 0001011 @sfence_vm +th_dcache_cva 0000001 00101 ..... 000 00000 0001011 @sfence_vm +th_dcache_civa 0000001 00111 ..... 000 00000 0001011 @sfence_vm +th_dcache_iva 0000001 00110 ..... 000 00000 0001011 @sfence_vm +th_dcache_csw 0000001 00001 ..... 000 00000 0001011 @sfence_vm +th_dcache_cisw 0000001 00011 ..... 000 00000 0001011 @sfence_vm +th_dcache_isw 0000001 00010 ..... 000 00000 0001011 @sfence_vm +th_dcache_cpal1 0000001 01000 ..... 000 00000 0001011 @sfence_vm +th_dcache_cval1 0000001 00100 ..... 000 00000 0001011 @sfence_vm +th_icache_iall 0000000 10000 00000 000 00000 0001011 +th_icache_ialls 0000000 10001 00000 000 00000 0001011 +th_icache_ipa 0000001 11000 ..... 000 00000 0001011 @sfence_vm +th_icache_iva 0000001 10000 ..... 000 00000 0001011 @sfence_vm +th_l2cache_call 0000000 10101 00000 000 00000 0001011 +th_l2cache_ciall 0000000 10111 00000 000 00000 0001011 +th_l2cache_iall 0000000 10110 00000 000 00000 0001011 From 134c3ffa34d005861f37cf6258b09df229e7be22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:01 +0100 Subject: [PATCH 584/814] RISC-V: Adding XTheadSync ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadSync ISA extension. The patch uses the T-Head specific decoder and translation. The implementation introduces a helper to execute synchronization tasks: helper_tlb_flush_all() performs a synchronized TLB flush on all CPUs. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-3-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/helper.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 85 ++++++++++++++++++++++ target/riscv/op_helper.c | 6 ++ target/riscv/translate.c | 2 +- target/riscv/xthead.decode | 9 +++ 7 files changed, 105 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6ea61e5b22..f76639845d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -110,6 +110,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), + ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; @@ -1090,6 +1091,7 @@ static Property riscv_cpu_extensions[] = { /* Vendor-specific custom extensions */ DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), + DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), /* These are experimental so mark with 'x-' */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index d3ebc6f112..ea00586436 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -474,6 +474,7 @@ struct RISCVCPUConfig { /* Vendor-specific custom extensions */ bool ext_xtheadcmo; + bool ext_xtheadsync; bool ext_XVentanaCondOps; uint8_t pmu_num; diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 58a30f03d6..0497370afd 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -109,6 +109,7 @@ DEF_HELPER_1(sret, tl, env) DEF_HELPER_1(mret, tl, env) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(tlb_flush, void, env) +DEF_HELPER_1(tlb_flush_all, void, env) /* Native Debug */ DEF_HELPER_1(itrigger_match, void, env) #endif diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 24acaf188c..f35bf6ea89 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -22,6 +22,12 @@ } \ } while (0) +#define REQUIRE_XTHEADSYNC(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadsync) { \ + return false; \ + } \ +} while (0) + /* XTheadCmo */ static inline int priv_level(DisasContext *ctx) @@ -79,3 +85,82 @@ NOP_PRIVCHECK(th_icache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) + +/* XTheadSync */ + +static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) +{ + (void) a; + REQUIRE_XTHEADSYNC(ctx); + +#ifndef CONFIG_USER_ONLY + REQUIRE_PRIV_MS(ctx); + gen_helper_tlb_flush_all(cpu_env); + return true; +#else + return false; +#endif +} + +#ifndef CONFIG_USER_ONLY +static void gen_th_sync_local(DisasContext *ctx) +{ + /* + * Emulate out-of-order barriers with pipeline flush + * by exiting the translation block. + */ + gen_set_pc_imm(ctx, ctx->pc_succ_insn); + tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_NORETURN; +} +#endif + +static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a) +{ + (void) a; + REQUIRE_XTHEADSYNC(ctx); + +#ifndef CONFIG_USER_ONLY + REQUIRE_PRIV_MSU(ctx); + + /* + * th.sync is an out-of-order barrier. + */ + gen_th_sync_local(ctx); + + return true; +#else + return false; +#endif +} + +static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a) +{ + (void) a; + REQUIRE_XTHEADSYNC(ctx); + +#ifndef CONFIG_USER_ONLY + REQUIRE_PRIV_MSU(ctx); + + /* + * th.sync.i is th.sync plus pipeline flush. + */ + gen_th_sync_local(ctx); + + return true; +#else + return false; +#endif +} + +static bool trans_th_sync_is(DisasContext *ctx, arg_th_sync_is *a) +{ + /* This instruction has the same behaviour like th.sync.i. */ + return trans_th_sync_i(ctx, a); +} + +static bool trans_th_sync_s(DisasContext *ctx, arg_th_sync_s *a) +{ + /* This instruction has the same behaviour like th.sync. */ + return trans_th_sync(ctx, a); +} diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 878bcb03b8..48f918b71b 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -258,6 +258,12 @@ void helper_tlb_flush(CPURISCVState *env) } } +void helper_tlb_flush_all(CPURISCVState *env) +{ + CPUState *cs = env_cpu(env); + tlb_flush_all_cpus_synced(cs); +} + void helper_hyp_tlb_flush(CPURISCVState *env) { CPUState *cs = env_cpu(env); diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 1e29ac9886..0657a4bea2 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -132,7 +132,7 @@ static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { - return ctx->cfg_ptr->ext_xtheadcmo; + return ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 30533a66f5..1d86f3a012 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -10,9 +10,11 @@ # Fields: %rs1 15:5 +%rs2 20:5 # Formats @sfence_vm ....... ..... ..... ... ..... ....... %rs1 +@rs2_s ....... ..... ..... ... ..... ....... %rs2 %rs1 # XTheadCmo th_dcache_call 0000000 00001 00000 000 00000 0001011 @@ -36,3 +38,10 @@ th_icache_iva 0000001 10000 ..... 000 00000 0001011 @sfence_vm th_l2cache_call 0000000 10101 00000 000 00000 0001011 th_l2cache_ciall 0000000 10111 00000 000 00000 0001011 th_l2cache_iall 0000000 10110 00000 000 00000 0001011 + +# XTheadSync +th_sfence_vmas 0000010 ..... ..... 000 00000 0001011 @rs2_s +th_sync 0000000 11000 00000 000 00000 0001011 +th_sync_i 0000000 11010 00000 000 00000 0001011 +th_sync_is 0000000 11011 00000 000 00000 0001011 +th_sync_s 0000000 11001 00000 000 00000 0001011 From c9410a689f9f8c79378bd6d806bac3495b1eb856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:02 +0100 Subject: [PATCH 585/814] RISC-V: Adding XTheadBa ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadBa ISA extension. The patch uses the T-Head specific decoder and translation. Co-developed-by: Philipp Tomsich Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-4-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 39 ++++++++++++++++++++++ target/riscv/translate.c | 3 +- target/riscv/xthead.decode | 22 ++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f76639845d..dd5ff82f22 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -109,6 +109,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval), ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), + ISA_EXT_DATA_ENTRY(xtheadba, true, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), @@ -1090,6 +1091,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false), /* Vendor-specific custom extensions */ + DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index ea00586436..f1f7795bd5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -473,6 +473,7 @@ struct RISCVCPUConfig { uint64_t mimpid; /* Vendor-specific custom extensions */ + bool ext_xtheadba; bool ext_xtheadcmo; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index f35bf6ea89..a6fb8132a8 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -16,6 +16,12 @@ * this program. If not, see . */ +#define REQUIRE_XTHEADBA(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadba) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADCMO(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadcmo) { \ return false; \ @@ -28,6 +34,39 @@ } \ } while (0) +/* XTheadBa */ + +/* + * th.addsl is similar to sh[123]add (from Zba), but not an + * alternative encoding: while sh[123] applies the shift to rs1, + * th.addsl shifts rs2. + */ + +#define GEN_TH_ADDSL(SHAMT) \ +static void gen_th_addsl##SHAMT(TCGv ret, TCGv arg1, TCGv arg2) \ +{ \ + TCGv t = tcg_temp_new(); \ + tcg_gen_shli_tl(t, arg2, SHAMT); \ + tcg_gen_add_tl(ret, t, arg1); \ + tcg_temp_free(t); \ +} + +GEN_TH_ADDSL(1) +GEN_TH_ADDSL(2) +GEN_TH_ADDSL(3) + +#define GEN_TRANS_TH_ADDSL(SHAMT) \ +static bool trans_th_addsl##SHAMT(DisasContext *ctx, \ + arg_th_addsl##SHAMT * a) \ +{ \ + REQUIRE_XTHEADBA(ctx); \ + return gen_arith(ctx, a, EXT_NONE, gen_th_addsl##SHAMT, NULL); \ +} + +GEN_TRANS_TH_ADDSL(1) +GEN_TRANS_TH_ADDSL(2) +GEN_TRANS_TH_ADDSL(3) + /* XTheadCmo */ static inline int priv_level(DisasContext *ctx) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 0657a4bea2..4683562ecf 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -132,7 +132,8 @@ static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { - return ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadsync; + return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadcmo || + ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 1d86f3a012..b149f13018 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -2,6 +2,7 @@ # Translation routines for the instructions of the XThead* ISA extensions # # Copyright (c) 2022 Christoph Muellner, christoph.muellner@vrull.eu +# Dr. Philipp Tomsich, philipp.tomsich@vrull.eu # # SPDX-License-Identifier: LGPL-2.1-or-later # @@ -9,12 +10,33 @@ # https://github.com/T-head-Semi/thead-extension-spec/releases/latest # Fields: +%rd 7:5 %rs1 15:5 %rs2 20:5 +# Argument sets +&r rd rs1 rs2 !extern + # Formats @sfence_vm ....... ..... ..... ... ..... ....... %rs1 @rs2_s ....... ..... ..... ... ..... ....... %rs2 %rs1 +@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd + +# XTheadBa +# Instead of defining a new encoding, we simply use the decoder to +# extract the imm[0:1] field and dispatch to separate translation +# functions (mirroring the `sh[123]add` instructions from Zba and +# the regular RVI `add` instruction. +# +# The only difference between sh[123]add and addsl is that the shift +# is applied to rs1 (for addsl) instead of rs2 (for sh[123]add). +# +# Note that shift-by-0 is a valid operation according to the manual. +# This will be equivalent to a regular add. +add 0000000 ..... ..... 001 ..... 0001011 @r +th_addsl1 0000001 ..... ..... 001 ..... 0001011 @r +th_addsl2 0000010 ..... ..... 001 ..... 0001011 @r +th_addsl3 0000011 ..... ..... 001 ..... 0001011 @r # XTheadCmo th_dcache_call 0000000 00001 00000 000 00000 0001011 From 426c049196efcdfc57511f779ec0416dd95a9cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:03 +0100 Subject: [PATCH 586/814] RISC-V: Adding XTheadBb ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadBb ISA extension. The patch uses the T-Head specific decoder and translation. Co-developed-by: Philipp Tomsich Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-5-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 124 +++++++++++++++++++++ target/riscv/translate.c | 4 +- target/riscv/xthead.decode | 20 ++++ 5 files changed, 149 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index dd5ff82f22..def27a53f2 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -110,6 +110,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), ISA_EXT_DATA_ENTRY(xtheadba, true, PRIV_VERSION_1_11_0, ext_xtheadba), + ISA_EXT_DATA_ENTRY(xtheadbb, true, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), @@ -1092,6 +1093,7 @@ static Property riscv_cpu_extensions[] = { /* Vendor-specific custom extensions */ DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false), + DEFINE_PROP_BOOL("xtheadbb", RISCVCPU, cfg.ext_xtheadbb, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f1f7795bd5..be86c2fb95 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -474,6 +474,7 @@ struct RISCVCPUConfig { /* Vendor-specific custom extensions */ bool ext_xtheadba; + bool ext_xtheadbb; bool ext_xtheadcmo; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index a6fb8132a8..ebfab90dd9 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -22,6 +22,12 @@ } \ } while (0) +#define REQUIRE_XTHEADBB(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadbb) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADCMO(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadcmo) { \ return false; \ @@ -67,6 +73,124 @@ GEN_TRANS_TH_ADDSL(1) GEN_TRANS_TH_ADDSL(2) GEN_TRANS_TH_ADDSL(3) +/* XTheadBb */ + +/* th.srri is an alternate encoding for rori (from Zbb) */ +static bool trans_th_srri(DisasContext *ctx, arg_th_srri * a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE, + tcg_gen_rotri_tl, gen_roriw, NULL); +} + +/* th.srriw is an alternate encoding for roriw (from Zbb) */ +static bool trans_th_srriw(DisasContext *ctx, arg_th_srriw *a) +{ + REQUIRE_XTHEADBB(ctx); + REQUIRE_64BIT(ctx); + ctx->ol = MXL_RV32; + return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw, NULL); +} + +/* th.ext and th.extu perform signed/unsigned bitfield extraction */ +static bool gen_th_bfextract(DisasContext *ctx, arg_th_bfext *a, + void (*f)(TCGv, TCGv, unsigned int, unsigned int)) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv source = get_gpr(ctx, a->rs1, EXT_ZERO); + + if (a->lsb <= a->msb) { + f(dest, source, a->lsb, a->msb - a->lsb + 1); + gen_set_gpr(ctx, a->rd, dest); + } + return true; +} + +static bool trans_th_ext(DisasContext *ctx, arg_th_ext *a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_th_bfextract(ctx, a, tcg_gen_sextract_tl); +} + +static bool trans_th_extu(DisasContext *ctx, arg_th_extu *a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_th_bfextract(ctx, a, tcg_gen_extract_tl); +} + +/* th.ff0: find first zero (clz on an inverted input) */ +static bool gen_th_ff0(DisasContext *ctx, arg_th_ff0 *a, DisasExtend ext) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1 = get_gpr(ctx, a->rs1, ext); + + int olen = get_olen(ctx); + TCGv t = tcg_temp_new(); + + tcg_gen_not_tl(t, src1); + if (olen != TARGET_LONG_BITS) { + if (olen == 32) { + gen_clzw(dest, t); + } else { + g_assert_not_reached(); + } + } else { + gen_clz(dest, t); + } + + tcg_temp_free(t); + gen_set_gpr(ctx, a->rd, dest); + + return true; +} + +static bool trans_th_ff0(DisasContext *ctx, arg_th_ff0 *a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_th_ff0(ctx, a, EXT_NONE); +} + +/* th.ff1 is an alternate encoding for clz (from Zbb) */ +static bool trans_th_ff1(DisasContext *ctx, arg_th_ff1 *a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw); +} + +static void gen_th_revw(TCGv ret, TCGv arg1) +{ + tcg_gen_bswap32_tl(ret, arg1, TCG_BSWAP_OS); +} + +/* th.rev is an alternate encoding for the RV64 rev8 (from Zbb) */ +static bool trans_th_rev(DisasContext *ctx, arg_th_rev *a) +{ + REQUIRE_XTHEADBB(ctx); + + return gen_unary_per_ol(ctx, a, EXT_NONE, tcg_gen_bswap_tl, gen_th_revw); +} + +/* th.revw is a sign-extended byte-swap of the lower word */ +static bool trans_th_revw(DisasContext *ctx, arg_th_revw *a) +{ + REQUIRE_XTHEADBB(ctx); + REQUIRE_64BIT(ctx); + return gen_unary(ctx, a, EXT_NONE, gen_th_revw); +} + +/* th.tstnbz is equivalent to an orc.b (from Zbb) with inverted result */ +static void gen_th_tstnbz(TCGv ret, TCGv source1) +{ + gen_orc_b(ret, source1); + tcg_gen_not_tl(ret, ret); +} + +static bool trans_th_tstnbz(DisasContext *ctx, arg_th_tstnbz *a) +{ + REQUIRE_XTHEADBB(ctx); + return gen_unary(ctx, a, EXT_ZERO, gen_th_tstnbz); +} + /* XTheadCmo */ static inline int priv_level(DisasContext *ctx) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 4683562ecf..387ef0ad8b 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -132,8 +132,8 @@ static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { - return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadcmo || - ctx->cfg_ptr->ext_xtheadsync; + return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || + ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index b149f13018..8cd140891b 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -13,14 +13,23 @@ %rd 7:5 %rs1 15:5 %rs2 20:5 +%sh5 20:5 +%sh6 20:6 # Argument sets &r rd rs1 rs2 !extern +&r2 rd rs1 !extern +&shift shamt rs1 rd !extern +&th_bfext msb lsb rs1 rd # Formats @sfence_vm ....... ..... ..... ... ..... ....... %rs1 @rs2_s ....... ..... ..... ... ..... ....... %rs2 %rs1 @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd +@r2 ....... ..... ..... ... ..... ....... &r2 %rs1 %rd +@th_bfext msb:6 lsb:6 ..... ... ..... ....... &th_bfext %rs1 %rd +@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd +@sh6 ...... ...... ..... ... ..... ....... &shift shamt=%sh6 %rs1 %rd # XTheadBa # Instead of defining a new encoding, we simply use the decoder to @@ -38,6 +47,17 @@ th_addsl1 0000001 ..... ..... 001 ..... 0001011 @r th_addsl2 0000010 ..... ..... 001 ..... 0001011 @r th_addsl3 0000011 ..... ..... 001 ..... 0001011 @r +# XTheadBb +th_ext ...... ...... ..... 010 ..... 0001011 @th_bfext +th_extu ...... ...... ..... 011 ..... 0001011 @th_bfext +th_ff0 1000010 00000 ..... 001 ..... 0001011 @r2 +th_ff1 1000011 00000 ..... 001 ..... 0001011 @r2 +th_srri 000100 ...... ..... 001 ..... 0001011 @sh6 +th_srriw 0001010 ..... ..... 001 ..... 0001011 @sh5 +th_rev 1000001 00000 ..... 001 ..... 0001011 @r2 +th_revw 1001000 00000 ..... 001 ..... 0001011 @r2 +th_tstnbz 1000000 00000 ..... 001 ..... 0001011 @r2 + # XTheadCmo th_dcache_call 0000000 00001 00000 000 00000 0001011 th_dcache_ciall 0000000 00011 00000 000 00000 0001011 From fa134585462897fc70a01d7b585fbc60371a7d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:04 +0100 Subject: [PATCH 587/814] RISC-V: Adding XTheadBs ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadBs ISA extension. The patch uses the T-Head specific decoder and translation. Co-developed-by: Philipp Tomsich Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-6-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 15 +++++++++++++++ target/riscv/translate.c | 3 ++- target/riscv/xthead.decode | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index def27a53f2..c541924214 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -111,6 +111,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt), ISA_EXT_DATA_ENTRY(xtheadba, true, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, true, PRIV_VERSION_1_11_0, ext_xtheadbb), + ISA_EXT_DATA_ENTRY(xtheadbs, true, PRIV_VERSION_1_11_0, ext_xtheadbs), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), @@ -1094,6 +1095,7 @@ static Property riscv_cpu_extensions[] = { /* Vendor-specific custom extensions */ DEFINE_PROP_BOOL("xtheadba", RISCVCPU, cfg.ext_xtheadba, false), DEFINE_PROP_BOOL("xtheadbb", RISCVCPU, cfg.ext_xtheadbb, false), + DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index be86c2fb95..876eaebd0e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -475,6 +475,7 @@ struct RISCVCPUConfig { /* Vendor-specific custom extensions */ bool ext_xtheadba; bool ext_xtheadbb; + bool ext_xtheadbs; bool ext_xtheadcmo; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index ebfab90dd9..bc1605445d 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -28,6 +28,12 @@ } \ } while (0) +#define REQUIRE_XTHEADBS(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadbs) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADCMO(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadcmo) { \ return false; \ @@ -191,6 +197,15 @@ static bool trans_th_tstnbz(DisasContext *ctx, arg_th_tstnbz *a) return gen_unary(ctx, a, EXT_ZERO, gen_th_tstnbz); } +/* XTheadBs */ + +/* th.tst is an alternate encoding for bexti (from Zbs) */ +static bool trans_th_tst(DisasContext *ctx, arg_th_tst *a) +{ + REQUIRE_XTHEADBS(ctx); + return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext); +} + /* XTheadCmo */ static inline int priv_level(DisasContext *ctx) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 387ef0ad8b..880324e617 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -133,7 +133,8 @@ static bool always_true_p(DisasContext *ctx __attribute__((__unused__))) static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || - ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || + ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 8cd140891b..8494805611 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -58,6 +58,9 @@ th_rev 1000001 00000 ..... 001 ..... 0001011 @r2 th_revw 1001000 00000 ..... 001 ..... 0001011 @r2 th_tstnbz 1000000 00000 ..... 001 ..... 0001011 @r2 +# XTheadBs +th_tst 100010 ...... ..... 001 ..... 0001011 @sh6 + # XTheadCmo th_dcache_call 0000000 00001 00000 000 00000 0001011 th_dcache_ciall 0000000 00011 00000 000 00000 0001011 From 3290933853c2c8a4a50a990cc395471097f0a173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:05 +0100 Subject: [PATCH 588/814] RISC-V: Adding XTheadCondMov ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadCondMov ISA extension. The patch uses the T-Head specific decoder and translation. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-7-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 35 ++++++++++++++++++++++ target/riscv/translate.c | 2 +- target/riscv/xthead.decode | 4 +++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index c541924214..13b065bc68 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -113,6 +113,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadbb, true, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, true, PRIV_VERSION_1_11_0, ext_xtheadbs), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), + ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; @@ -1097,6 +1098,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadbb", RISCVCPU, cfg.ext_xtheadbb, false), DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), + DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 876eaebd0e..a313e025e7 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -477,6 +477,7 @@ struct RISCVCPUConfig { bool ext_xtheadbb; bool ext_xtheadbs; bool ext_xtheadcmo; + bool ext_xtheadcondmov; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index bc1605445d..089b51f468 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -40,6 +40,12 @@ } \ } while (0) +#define REQUIRE_XTHEADCONDMOV(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadcondmov) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADSYNC(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadsync) { \ return false; \ @@ -264,6 +270,35 @@ NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +/* XTheadCondMov */ + +static bool gen_th_condmove(DisasContext *ctx, arg_r *a, TCGCond cond) +{ + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv old = get_gpr(ctx, a->rd, EXT_NONE); + TCGv dest = dest_gpr(ctx, a->rd); + + tcg_gen_movcond_tl(cond, dest, src2, ctx->zero, src1, old); + + gen_set_gpr(ctx, a->rd, dest); + return true; +} + +/* th.mveqz: "if (rs2 == 0) rd = rs1;" */ +static bool trans_th_mveqz(DisasContext *ctx, arg_th_mveqz *a) +{ + REQUIRE_XTHEADCONDMOV(ctx); + return gen_th_condmove(ctx, a, TCG_COND_EQ); +} + +/* th.mvnez: "if (rs2 != 0) rd = rs1;" */ +static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a) +{ + REQUIRE_XTHEADCONDMOV(ctx); + return gen_th_condmove(ctx, a, TCG_COND_NE); +} + /* XTheadSync */ static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 880324e617..4f4c09cd68 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -134,7 +134,7 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || - ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 8494805611..a8ebd8a18b 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -84,6 +84,10 @@ th_l2cache_call 0000000 10101 00000 000 00000 0001011 th_l2cache_ciall 0000000 10111 00000 000 00000 0001011 th_l2cache_iall 0000000 10110 00000 000 00000 0001011 +# XTheadCondMov +th_mveqz 0100000 ..... ..... 001 ..... 0001011 @r +th_mvnez 0100001 ..... ..... 001 ..... 0001011 @r + # XTheadSync th_sfence_vmas 0000010 ..... ..... 000 00000 0001011 @rs2_s th_sync 0000000 11000 00000 000 00000 0001011 From b8a5832b87fb513725cd6d960cae6476f3a515c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:06 +0100 Subject: [PATCH 589/814] RISC-V: Adding T-Head multiply-accumulate instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the T-Head MAC instructions. The patch uses the T-Head specific decoder and translation. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-8-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 83 ++++++++++++++++++++++ target/riscv/translate.c | 3 +- target/riscv/xthead.decode | 8 +++ 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 13b065bc68..88da4de14d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -114,6 +114,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadbs, true, PRIV_VERSION_1_11_0, ext_xtheadbs), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), + ISA_EXT_DATA_ENTRY(xtheadmac, true, PRIV_VERSION_1_11_0, ext_xtheadmac), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; @@ -1099,6 +1100,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), + DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a313e025e7..830b20558c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -478,6 +478,7 @@ struct RISCVCPUConfig { bool ext_xtheadbs; bool ext_xtheadcmo; bool ext_xtheadcondmov; + bool ext_xtheadmac; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 089b51f468..31a4034927 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -46,6 +46,12 @@ } \ } while (0) +#define REQUIRE_XTHEADMAC(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadmac) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADSYNC(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadsync) { \ return false; \ @@ -299,6 +305,83 @@ static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a) return gen_th_condmove(ctx, a, TCG_COND_NE); } +/* XTheadMac */ + +static bool gen_th_mac(DisasContext *ctx, arg_r *a, + void (*accumulate_func)(TCGv, TCGv, TCGv), + void (*extend_operand_func)(TCGv, TCGv)) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src0 = get_gpr(ctx, a->rd, EXT_NONE); + TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv tmp = tcg_temp_new(); + + if (extend_operand_func) { + TCGv tmp2 = tcg_temp_new(); + extend_operand_func(tmp, src1); + extend_operand_func(tmp2, src2); + tcg_gen_mul_tl(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + } else { + tcg_gen_mul_tl(tmp, src1, src2); + } + + accumulate_func(dest, src0, tmp); + gen_set_gpr(ctx, a->rd, dest); + tcg_temp_free(tmp); + + return true; +} + +/* th.mula: "rd = rd + rs1 * rs2" */ +static bool trans_th_mula(DisasContext *ctx, arg_th_mula *a) +{ + REQUIRE_XTHEADMAC(ctx); + return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL); +} + +/* th.mulah: "rd = sext.w(rd + sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */ +static bool trans_th_mulah(DisasContext *ctx, arg_th_mulah *a) +{ + REQUIRE_XTHEADMAC(ctx); + ctx->ol = MXL_RV32; + return gen_th_mac(ctx, a, tcg_gen_add_tl, tcg_gen_ext16s_tl); +} + +/* th.mulaw: "rd = sext.w(rd + rs1 * rs2)" */ +static bool trans_th_mulaw(DisasContext *ctx, arg_th_mulaw *a) +{ + REQUIRE_XTHEADMAC(ctx); + REQUIRE_64BIT(ctx); + ctx->ol = MXL_RV32; + return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL); +} + +/* th.muls: "rd = rd - rs1 * rs2" */ +static bool trans_th_muls(DisasContext *ctx, arg_th_muls *a) +{ + REQUIRE_XTHEADMAC(ctx); + return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL); +} + +/* th.mulsh: "rd = sext.w(rd - sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */ +static bool trans_th_mulsh(DisasContext *ctx, arg_th_mulsh *a) +{ + REQUIRE_XTHEADMAC(ctx); + ctx->ol = MXL_RV32; + return gen_th_mac(ctx, a, tcg_gen_sub_tl, tcg_gen_ext16s_tl); +} + +/* th.mulsw: "rd = sext.w(rd - rs1 * rs2)" */ +static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a) +{ + REQUIRE_XTHEADMAC(ctx); + REQUIRE_64BIT(ctx); + ctx->ol = MXL_RV32; + return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL); +} + /* XTheadSync */ static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 4f4c09cd68..e5a57a8516 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -134,7 +134,8 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || - ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadmac || + ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index a8ebd8a18b..696de6cecf 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -88,6 +88,14 @@ th_l2cache_iall 0000000 10110 00000 000 00000 0001011 th_mveqz 0100000 ..... ..... 001 ..... 0001011 @r th_mvnez 0100001 ..... ..... 001 ..... 0001011 @r +# XTheadMac +th_mula 00100 00 ..... ..... 001 ..... 0001011 @r +th_mulah 00101 00 ..... ..... 001 ..... 0001011 @r +th_mulaw 00100 10 ..... ..... 001 ..... 0001011 @r +th_muls 00100 01 ..... ..... 001 ..... 0001011 @r +th_mulsh 00101 01 ..... ..... 001 ..... 0001011 @r +th_mulsw 00100 11 ..... ..... 001 ..... 0001011 @r + # XTheadSync th_sfence_vmas 0000010 ..... ..... 000 00000 0001011 @rs2_s th_sync 0000000 11000 00000 000 00000 0001011 From af99aa72ef4576693208b827c975fac57c8b6fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:07 +0100 Subject: [PATCH 590/814] RISC-V: Adding T-Head MemPair extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the T-Head MemPair instructions. The patch uses the T-Head specific decoder and translation. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-9-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 92 ++++++++++++++++++++++ target/riscv/translate.c | 2 +- target/riscv/xthead.decode | 13 +++ 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 88da4de14d..b7047d139d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -115,6 +115,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), ISA_EXT_DATA_ENTRY(xtheadmac, true, PRIV_VERSION_1_11_0, ext_xtheadmac), + ISA_EXT_DATA_ENTRY(xtheadmempair, true, PRIV_VERSION_1_11_0, ext_xtheadmempair), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), }; @@ -1101,6 +1102,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), + DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 830b20558c..38e80d44d5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -479,6 +479,7 @@ struct RISCVCPUConfig { bool ext_xtheadcmo; bool ext_xtheadcondmov; bool ext_xtheadmac; + bool ext_xtheadmempair; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 31a4034927..f1bd0dbad5 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -52,6 +52,12 @@ } \ } while (0) +#define REQUIRE_XTHEADMEMPAIR(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadmempair) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADSYNC(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadsync) { \ return false; \ @@ -382,6 +388,92 @@ static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a) return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL); } +/* XTheadMemPair */ + +static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop, + int shamt) +{ + if (a->rs == a->rd1 || a->rs == a->rd2 || a->rd1 == a->rd2) { + return false; + } + + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + TCGv addr1 = tcg_temp_new(); + TCGv addr2 = tcg_temp_new(); + int imm = a->sh2 << shamt; + + addr1 = get_address(ctx, a->rs, imm); + addr2 = get_address(ctx, a->rs, memop_size(memop) + imm); + + tcg_gen_qemu_ld_tl(t1, addr1, ctx->mem_idx, memop); + tcg_gen_qemu_ld_tl(t2, addr2, ctx->mem_idx, memop); + gen_set_gpr(ctx, a->rd1, t1); + gen_set_gpr(ctx, a->rd2, t2); + + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(addr1); + tcg_temp_free(addr2); + return true; +} + +static bool trans_th_ldd(DisasContext *ctx, arg_th_pair *a) +{ + REQUIRE_XTHEADMEMPAIR(ctx); + REQUIRE_64BIT(ctx); + return gen_loadpair_tl(ctx, a, MO_TESQ, 4); +} + +static bool trans_th_lwd(DisasContext *ctx, arg_th_pair *a) +{ + REQUIRE_XTHEADMEMPAIR(ctx); + return gen_loadpair_tl(ctx, a, MO_TESL, 3); +} + +static bool trans_th_lwud(DisasContext *ctx, arg_th_pair *a) +{ + REQUIRE_XTHEADMEMPAIR(ctx); + return gen_loadpair_tl(ctx, a, MO_TEUL, 3); +} + +static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop, + int shamt) +{ + if (a->rs == a->rd1 || a->rs == a->rd2 || a->rd1 == a->rd2) { + return false; + } + + TCGv data1 = get_gpr(ctx, a->rd1, EXT_NONE); + TCGv data2 = get_gpr(ctx, a->rd2, EXT_NONE); + TCGv addr1 = tcg_temp_new(); + TCGv addr2 = tcg_temp_new(); + int imm = a->sh2 << shamt; + + addr1 = get_address(ctx, a->rs, imm); + addr2 = get_address(ctx, a->rs, memop_size(memop) + imm); + + tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop); + tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop); + + tcg_temp_free(addr1); + tcg_temp_free(addr2); + return true; +} + +static bool trans_th_sdd(DisasContext *ctx, arg_th_pair *a) +{ + REQUIRE_XTHEADMEMPAIR(ctx); + REQUIRE_64BIT(ctx); + return gen_storepair_tl(ctx, a, MO_TESQ, 4); +} + +static bool trans_th_swd(DisasContext *ctx, arg_th_pair *a) +{ + REQUIRE_XTHEADMEMPAIR(ctx); + return gen_storepair_tl(ctx, a, MO_TESL, 3); +} + /* XTheadSync */ static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index e5a57a8516..f383e69db3 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -135,7 +135,7 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadmac || - ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 696de6cecf..ff2a83b56d 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -11,16 +11,21 @@ # Fields: %rd 7:5 +%rd1 7:5 +%rs 15:5 %rs1 15:5 +%rd2 20:5 %rs2 20:5 %sh5 20:5 %sh6 20:6 +%sh2 25:2 # Argument sets &r rd rs1 rs2 !extern &r2 rd rs1 !extern &shift shamt rs1 rd !extern &th_bfext msb lsb rs1 rd +&th_pair rd1 rs rd2 sh2 # Formats @sfence_vm ....... ..... ..... ... ..... ....... %rs1 @@ -30,6 +35,7 @@ @th_bfext msb:6 lsb:6 ..... ... ..... ....... &th_bfext %rs1 %rd @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd @sh6 ...... ...... ..... ... ..... ....... &shift shamt=%sh6 %rs1 %rd +@th_pair ..... .. ..... ..... ... ..... ....... &th_pair %rd1 %rs %rd2 %sh2 # XTheadBa # Instead of defining a new encoding, we simply use the decoder to @@ -96,6 +102,13 @@ th_muls 00100 01 ..... ..... 001 ..... 0001011 @r th_mulsh 00101 01 ..... ..... 001 ..... 0001011 @r th_mulsw 00100 11 ..... ..... 001 ..... 0001011 @r +# XTheadMemPair +th_ldd 11111 .. ..... ..... 100 ..... 0001011 @th_pair +th_lwd 11100 .. ..... ..... 100 ..... 0001011 @th_pair +th_lwud 11110 .. ..... ..... 100 ..... 0001011 @th_pair +th_sdd 11111 .. ..... ..... 101 ..... 0001011 @th_pair +th_swd 11100 .. ..... ..... 101 ..... 0001011 @th_pair + # XTheadSync th_sfence_vmas 0000010 ..... ..... 000 00000 0001011 @rs2_s th_sync 0000000 11000 00000 000 00000 0001011 From 45f9df86db487573dc9a5e12e2afdb219d399a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:08 +0100 Subject: [PATCH 591/814] RISC-V: Adding T-Head MemIdx extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the T-Head MemIdx instructions. The patch uses the T-Head specific decoder and translation. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-10-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 387 +++++++++++++++++++++ target/riscv/translate.c | 21 +- target/riscv/xthead.decode | 54 +++ 5 files changed, 464 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b7047d139d..2d5a0881f1 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -115,6 +115,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), ISA_EXT_DATA_ENTRY(xtheadmac, true, PRIV_VERSION_1_11_0, ext_xtheadmac), + ISA_EXT_DATA_ENTRY(xtheadmemidx, true, PRIV_VERSION_1_11_0, ext_xtheadmemidx), ISA_EXT_DATA_ENTRY(xtheadmempair, true, PRIV_VERSION_1_11_0, ext_xtheadmempair), ISA_EXT_DATA_ENTRY(xtheadsync, true, PRIV_VERSION_1_11_0, ext_xtheadsync), ISA_EXT_DATA_ENTRY(xventanacondops, true, PRIV_VERSION_1_12_0, ext_XVentanaCondOps), @@ -1102,6 +1103,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), + DEFINE_PROP_BOOL("xtheadmemidx", RISCVCPU, cfg.ext_xtheadmemidx, false), DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false), DEFINE_PROP_BOOL("xtheadsync", RISCVCPU, cfg.ext_xtheadsync, false), DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 38e80d44d5..d776fea760 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -479,6 +479,7 @@ struct RISCVCPUConfig { bool ext_xtheadcmo; bool ext_xtheadcondmov; bool ext_xtheadmac; + bool ext_xtheadmemidx; bool ext_xtheadmempair; bool ext_xtheadsync; bool ext_XVentanaCondOps; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index f1bd0dbad5..8167de0393 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -52,6 +52,12 @@ } \ } while (0) +#define REQUIRE_XTHEADMEMIDX(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadmemidx) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADMEMPAIR(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadmempair) { \ return false; \ @@ -64,6 +70,30 @@ } \ } while (0) +/* + * Calculate and return the address for indexed mem operations: + * If !zext_offs, then the address is rs1 + (rs2 << imm2). + * If zext_offs, then the address is rs1 + (zext(rs2[31:0]) << imm2). + */ +static TCGv get_th_address_indexed(DisasContext *ctx, int rs1, int rs2, + int imm2, bool zext_offs) +{ + TCGv src2 = get_gpr(ctx, rs2, EXT_NONE); + TCGv offs = tcg_temp_new(); + + if (zext_offs) { + tcg_gen_extract_tl(offs, src2, 0, 32); + tcg_gen_shli_tl(offs, offs, imm2); + } else { + tcg_gen_shli_tl(offs, src2, imm2); + } + + TCGv addr = get_address_indexed(ctx, rs1, offs); + + tcg_temp_free(offs); + return addr; +} + /* XTheadBa */ /* @@ -388,6 +418,363 @@ static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a) return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL); } +/* XTheadMemIdx */ + +/* + * Load with memop from indexed address and add (imm5 << imm2) to rs1. + * If !preinc, then the load address is rs1. + * If preinc, then the load address is rs1 + (imm5) << imm2). + */ +static bool gen_load_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop, + bool preinc) +{ + if (a->rs1 == a->rd) { + return false; + } + + int imm = a->imm5 << a->imm2; + TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0); + TCGv rd = dest_gpr(ctx, a->rd); + TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE); + + tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop); + tcg_gen_addi_tl(rs1, rs1, imm); + gen_set_gpr(ctx, a->rd, rd); + gen_set_gpr(ctx, a->rs1, rs1); + + tcg_temp_free(addr); + return true; +} + +/* + * Store with memop to indexed address and add (imm5 << imm2) to rs1. + * If !preinc, then the store address is rs1. + * If preinc, then the store address is rs1 + (imm5) << imm2). + */ +static bool gen_store_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop, + bool preinc) +{ + int imm = a->imm5 << a->imm2; + TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0); + TCGv data = get_gpr(ctx, a->rd, EXT_NONE); + TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE); + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); + tcg_gen_addi_tl(rs1, rs1, imm); + gen_set_gpr(ctx, a->rs1, rs1); + + tcg_temp_free(addr); + return true; +} + +static bool trans_th_ldia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_inc(ctx, a, MO_TESQ, false); +} + +static bool trans_th_ldib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_inc(ctx, a, MO_TESQ, true); +} + +static bool trans_th_lwia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TESL, false); +} + +static bool trans_th_lwib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TESL, true); +} + +static bool trans_th_lwuia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_inc(ctx, a, MO_TEUL, false); +} + +static bool trans_th_lwuib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_inc(ctx, a, MO_TEUL, true); +} + +static bool trans_th_lhia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TESW, false); +} + +static bool trans_th_lhib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TESW, true); +} + +static bool trans_th_lhuia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TEUW, false); +} + +static bool trans_th_lhuib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_TEUW, true); +} + +static bool trans_th_lbia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_SB, false); +} + +static bool trans_th_lbib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_SB, true); +} + +static bool trans_th_lbuia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_UB, false); +} + +static bool trans_th_lbuib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_inc(ctx, a, MO_UB, true); +} + +static bool trans_th_sdia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_store_inc(ctx, a, MO_TESQ, false); +} + +static bool trans_th_sdib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_store_inc(ctx, a, MO_TESQ, true); +} + +static bool trans_th_swia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_TESL, false); +} + +static bool trans_th_swib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_TESL, true); +} + +static bool trans_th_shia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_TESW, false); +} + +static bool trans_th_shib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_TESW, true); +} + +static bool trans_th_sbia(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_SB, false); +} + +static bool trans_th_sbib(DisasContext *ctx, arg_th_meminc *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_inc(ctx, a, MO_SB, true); +} + +/* + * Load with memop from indexed address. + * If !zext_offs, then address is rs1 + (rs2 << imm2). + * If zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2). + */ +static bool gen_load_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop, + bool zext_offs) +{ + TCGv rd = dest_gpr(ctx, a->rd); + TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs); + + tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop); + gen_set_gpr(ctx, a->rd, rd); + + return true; +} + +/* + * Store with memop to indexed address. + * If !zext_offs, then address is rs1 + (rs2 << imm2). + * If zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2). + */ +static bool gen_store_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop, + bool zext_offs) +{ + TCGv data = get_gpr(ctx, a->rd, EXT_NONE); + TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs); + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); + + return true; +} + +static bool trans_th_lrd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_idx(ctx, a, MO_TESQ, false); +} + +static bool trans_th_lrw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TESL, false); +} + +static bool trans_th_lrwu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_idx(ctx, a, MO_TEUL, false); +} + +static bool trans_th_lrh(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TESW, false); +} + +static bool trans_th_lrhu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TEUW, false); +} + +static bool trans_th_lrb(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_SB, false); +} + +static bool trans_th_lrbu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_UB, false); +} + +static bool trans_th_srd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_store_idx(ctx, a, MO_TESQ, false); +} + +static bool trans_th_srw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_TESL, false); +} + +static bool trans_th_srh(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_TESW, false); +} + +static bool trans_th_srb(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_SB, false); +} +static bool trans_th_lurd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_idx(ctx, a, MO_TESQ, true); +} + +static bool trans_th_lurw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TESL, true); +} + +static bool trans_th_lurwu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_load_idx(ctx, a, MO_TEUL, true); +} + +static bool trans_th_lurh(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TESW, true); +} + +static bool trans_th_lurhu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_TEUW, true); +} + +static bool trans_th_lurb(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_SB, true); +} + +static bool trans_th_lurbu(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_load_idx(ctx, a, MO_UB, true); +} + +static bool trans_th_surd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + REQUIRE_64BIT(ctx); + return gen_store_idx(ctx, a, MO_TESQ, true); +} + +static bool trans_th_surw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_TESL, true); +} + +static bool trans_th_surh(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_TESW, true); +} + +static bool trans_th_surb(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADMEMIDX(ctx); + return gen_store_idx(ctx, a, MO_SB, true); +} + /* XTheadMemPair */ static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop, diff --git a/target/riscv/translate.c b/target/riscv/translate.c index f383e69db3..a979d43a6a 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -135,7 +135,8 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadmac || - ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadmemidx || ctx->cfg_ptr->ext_xtheadmempair || + ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ @@ -597,6 +598,24 @@ static TCGv get_address(DisasContext *ctx, int rs1, int imm) return addr; } +/* Compute a canonical address from a register plus reg offset. */ +static TCGv get_address_indexed(DisasContext *ctx, int rs1, TCGv offs) +{ + TCGv addr = temp_new(ctx); + TCGv src1 = get_gpr(ctx, rs1, EXT_NONE); + + tcg_gen_add_tl(addr, src1, offs); + if (ctx->pm_mask_enabled) { + tcg_gen_andc_tl(addr, addr, pm_mask); + } else if (get_xl(ctx) == MXL_RV32) { + tcg_gen_ext32u_tl(addr, addr); + } + if (ctx->pm_base_enabled) { + tcg_gen_or_tl(addr, addr, pm_base); + } + return addr; +} + #ifndef CONFIG_USER_ONLY /* The states of mstatus_fs are: * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index ff2a83b56d..69e40f22dc 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -17,8 +17,10 @@ %rd2 20:5 %rs2 20:5 %sh5 20:5 +%imm5 20:s5 %sh6 20:6 %sh2 25:2 +%imm2 25:2 # Argument sets &r rd rs1 rs2 !extern @@ -26,6 +28,8 @@ &shift shamt rs1 rd !extern &th_bfext msb lsb rs1 rd &th_pair rd1 rs rd2 sh2 +&th_memidx rd rs1 rs2 imm2 +&th_meminc rd rs1 imm5 imm2 # Formats @sfence_vm ....... ..... ..... ... ..... ....... %rs1 @@ -36,6 +40,8 @@ @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd @sh6 ...... ...... ..... ... ..... ....... &shift shamt=%sh6 %rs1 %rd @th_pair ..... .. ..... ..... ... ..... ....... &th_pair %rd1 %rs %rd2 %sh2 +@th_memidx ..... .. ..... ..... ... ..... ....... &th_memidx %rd %rs1 %rs2 %imm2 +@th_meminc ..... .. ..... ..... ... ..... ....... &th_meminc %rd %rs1 %imm5 %imm2 # XTheadBa # Instead of defining a new encoding, we simply use the decoder to @@ -102,6 +108,54 @@ th_muls 00100 01 ..... ..... 001 ..... 0001011 @r th_mulsh 00101 01 ..... ..... 001 ..... 0001011 @r th_mulsw 00100 11 ..... ..... 001 ..... 0001011 @r +# XTheadMemIdx +th_ldia 01111 .. ..... ..... 100 ..... 0001011 @th_meminc +th_ldib 01101 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lwia 01011 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lwib 01001 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lwuia 11011 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lwuib 11001 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lhia 00111 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lhib 00101 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lhuia 10111 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lhuib 10101 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lbia 00011 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lbib 00001 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lbuia 10011 .. ..... ..... 100 ..... 0001011 @th_meminc +th_lbuib 10001 .. ..... ..... 100 ..... 0001011 @th_meminc +th_sdia 01111 .. ..... ..... 101 ..... 0001011 @th_meminc +th_sdib 01101 .. ..... ..... 101 ..... 0001011 @th_meminc +th_swia 01011 .. ..... ..... 101 ..... 0001011 @th_meminc +th_swib 01001 .. ..... ..... 101 ..... 0001011 @th_meminc +th_shia 00111 .. ..... ..... 101 ..... 0001011 @th_meminc +th_shib 00101 .. ..... ..... 101 ..... 0001011 @th_meminc +th_sbia 00011 .. ..... ..... 101 ..... 0001011 @th_meminc +th_sbib 00001 .. ..... ..... 101 ..... 0001011 @th_meminc + +th_lrd 01100 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrw 01000 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrwu 11000 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrh 00100 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrhu 10100 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrb 00000 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lrbu 10000 .. ..... ..... 100 ..... 0001011 @th_memidx +th_srd 01100 .. ..... ..... 101 ..... 0001011 @th_memidx +th_srw 01000 .. ..... ..... 101 ..... 0001011 @th_memidx +th_srh 00100 .. ..... ..... 101 ..... 0001011 @th_memidx +th_srb 00000 .. ..... ..... 101 ..... 0001011 @th_memidx + +th_lurd 01110 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurw 01010 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurwu 11010 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurh 00110 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurhu 10110 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurb 00010 .. ..... ..... 100 ..... 0001011 @th_memidx +th_lurbu 10010 .. ..... ..... 100 ..... 0001011 @th_memidx +th_surd 01110 .. ..... ..... 101 ..... 0001011 @th_memidx +th_surw 01010 .. ..... ..... 101 ..... 0001011 @th_memidx +th_surh 00110 .. ..... ..... 101 ..... 0001011 @th_memidx +th_surb 00010 .. ..... ..... 101 ..... 0001011 @th_memidx + # XTheadMemPair th_ldd 11111 .. ..... ..... 100 ..... 0001011 @th_pair th_lwd 11100 .. ..... ..... 100 ..... 0001011 @th_pair From d4d901157e9fd323a155fdaf4d938afcafd7b857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:09 +0100 Subject: [PATCH 592/814] RISC-V: Adding T-Head FMemIdx extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the T-Head FMemIdx instructions. The patch uses the T-Head specific decoder and translation. Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-11-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 108 +++++++++++++++++++++ target/riscv/translate.c | 3 +- target/riscv/xthead.decode | 10 ++ 5 files changed, 123 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2d5a0881f1..5679e2cb83 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -114,6 +114,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadbs, true, PRIV_VERSION_1_11_0, ext_xtheadbs), ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), + ISA_EXT_DATA_ENTRY(xtheadfmemidx, true, PRIV_VERSION_1_11_0, ext_xtheadfmemidx), ISA_EXT_DATA_ENTRY(xtheadmac, true, PRIV_VERSION_1_11_0, ext_xtheadmac), ISA_EXT_DATA_ENTRY(xtheadmemidx, true, PRIV_VERSION_1_11_0, ext_xtheadmemidx), ISA_EXT_DATA_ENTRY(xtheadmempair, true, PRIV_VERSION_1_11_0, ext_xtheadmempair), @@ -1102,6 +1103,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadbs", RISCVCPU, cfg.ext_xtheadbs, false), DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), + DEFINE_PROP_BOOL("xtheadfmemidx", RISCVCPU, cfg.ext_xtheadfmemidx, false), DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), DEFINE_PROP_BOOL("xtheadmemidx", RISCVCPU, cfg.ext_xtheadmemidx, false), DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index d776fea760..5cc3011529 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -478,6 +478,7 @@ struct RISCVCPUConfig { bool ext_xtheadbs; bool ext_xtheadcmo; bool ext_xtheadcondmov; + bool ext_xtheadfmemidx; bool ext_xtheadmac; bool ext_xtheadmemidx; bool ext_xtheadmempair; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 8167de0393..37373732f6 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -46,6 +46,12 @@ } \ } while (0) +#define REQUIRE_XTHEADFMEMIDX(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadfmemidx) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADMAC(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadmac) { \ return false; \ @@ -341,6 +347,108 @@ static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a) return gen_th_condmove(ctx, a, TCG_COND_NE); } +/* XTheadFMem */ + +/* + * Load 64-bit float from indexed address. + * If !zext_offs, then address is rs1 + (rs2 << imm2). + * If zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2). + */ +static bool gen_fload_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop, + bool zext_offs) +{ + TCGv_i64 rd = cpu_fpr[a->rd]; + TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs); + + tcg_gen_qemu_ld_i64(rd, addr, ctx->mem_idx, memop); + if ((memop & MO_SIZE) == MO_32) { + gen_nanbox_s(rd, rd); + } + + mark_fs_dirty(ctx); + return true; +} + +/* + * Store 64-bit float to indexed address. + * If !zext_offs, then address is rs1 + (rs2 << imm2). + * If zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2). + */ +static bool gen_fstore_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop, + bool zext_offs) +{ + TCGv_i64 rd = cpu_fpr[a->rd]; + TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs); + + tcg_gen_qemu_st_i64(rd, addr, ctx->mem_idx, memop); + + return true; +} + +static bool trans_th_flrd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + return gen_fload_idx(ctx, a, MO_TEUQ, false); +} + +static bool trans_th_flrw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + return gen_fload_idx(ctx, a, MO_TEUL, false); +} + +static bool trans_th_flurd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + return gen_fload_idx(ctx, a, MO_TEUQ, true); +} + +static bool trans_th_flurw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + return gen_fload_idx(ctx, a, MO_TEUL, true); +} + +static bool trans_th_fsrd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + return gen_fstore_idx(ctx, a, MO_TEUQ, false); +} + +static bool trans_th_fsrw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + return gen_fstore_idx(ctx, a, MO_TEUL, false); +} + +static bool trans_th_fsurd(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + return gen_fstore_idx(ctx, a, MO_TEUQ, true); +} + +static bool trans_th_fsurw(DisasContext *ctx, arg_th_memidx *a) +{ + REQUIRE_XTHEADFMEMIDX(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVF); + return gen_fstore_idx(ctx, a, MO_TEUL, true); +} + /* XTheadMac */ static bool gen_th_mac(DisasContext *ctx, arg_r *a, diff --git a/target/riscv/translate.c b/target/riscv/translate.c index a979d43a6a..216eaf9d12 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -134,7 +134,8 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) { return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || - ctx->cfg_ptr->ext_xtheadcondmov || ctx->cfg_ptr->ext_xtheadmac || + ctx->cfg_ptr->ext_xtheadcondmov || + ctx->cfg_ptr->ext_xtheadfmemidx || ctx->cfg_ptr->ext_xtheadmac || ctx->cfg_ptr->ext_xtheadmemidx || ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync; } diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 69e40f22dc..81daf1d694 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -100,6 +100,16 @@ th_l2cache_iall 0000000 10110 00000 000 00000 0001011 th_mveqz 0100000 ..... ..... 001 ..... 0001011 @r th_mvnez 0100001 ..... ..... 001 ..... 0001011 @r +# XTheadFMemIdx +th_flrd 01100 .. ..... ..... 110 ..... 0001011 @th_memidx +th_flrw 01000 .. ..... ..... 110 ..... 0001011 @th_memidx +th_flurd 01110 .. ..... ..... 110 ..... 0001011 @th_memidx +th_flurw 01010 .. ..... ..... 110 ..... 0001011 @th_memidx +th_fsrd 01100 .. ..... ..... 111 ..... 0001011 @th_memidx +th_fsrw 01000 .. ..... ..... 111 ..... 0001011 @th_memidx +th_fsurd 01110 .. ..... ..... 111 ..... 0001011 @th_memidx +th_fsurw 01010 .. ..... ..... 111 ..... 0001011 @th_memidx + # XTheadMac th_mula 00100 00 ..... ..... 001 ..... 0001011 @r th_mulah 00101 00 ..... ..... 001 ..... 0001011 @r From 7ad2878cfd8356e1b9c1097edae367507c182066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:10 +0100 Subject: [PATCH 593/814] RISC-V: Set minimum priv version for Zfh to 1.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are no differences for floating point instructions in priv version 1.11 and 1.12. There is also no dependency for Zfh to priv version 1.12. Therefore allow Zfh to be enabled for priv version 1.11. Acked-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-12-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5679e2cb83..3078556f1b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -77,7 +77,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei), ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause), ISA_EXT_DATA_ENTRY(zawrs, true, PRIV_VERSION_1_12_0, ext_zawrs), - ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_12_0, ext_zfh), + ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_11_0, ext_zfh), ISA_EXT_DATA_ENTRY(zfhmin, true, PRIV_VERSION_1_12_0, ext_zfhmin), ISA_EXT_DATA_ENTRY(zfinx, true, PRIV_VERSION_1_12_0, ext_zfinx), ISA_EXT_DATA_ENTRY(zdinx, true, PRIV_VERSION_1_12_0, ext_zdinx), From 95bd8daaafdff905ee4fa0620c097ad4eb2e8a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:11 +0100 Subject: [PATCH 594/814] RISC-V: Add initial support for T-Head C906 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the T-Head C906 to the list of known CPUs. Selecting this CPUs will automatically enable the available ISA extensions of the CPUs (incl. vendor extensions). Co-developed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-13-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 31 +++++++++++++++++++++++++++++++ target/riscv/cpu.h | 1 + target/riscv/cpu_vendorid.h | 6 ++++++ 3 files changed, 38 insertions(+) create mode 100644 target/riscv/cpu_vendorid.h diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 3078556f1b..8cbc5c9c1b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -22,6 +22,7 @@ #include "qemu/ctype.h" #include "qemu/log.h" #include "cpu.h" +#include "cpu_vendorid.h" #include "pmu.h" #include "internals.h" #include "time_helper.h" @@ -281,6 +282,35 @@ static void rv64_sifive_e_cpu_init(Object *obj) cpu->cfg.mmu = false; } +static void rv64_thead_c906_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + set_priv_version(env, PRIV_VERSION_1_11_0); + + cpu->cfg.ext_g = true; + cpu->cfg.ext_c = true; + cpu->cfg.ext_u = true; + cpu->cfg.ext_s = true; + cpu->cfg.ext_icsr = 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; +} + static void rv128_base_cpu_init(Object *obj) { if (qemu_tcg_mttcg_enabled()) { @@ -1371,6 +1401,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_THEAD_C906, rv64_thead_c906_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), #endif }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5cc3011529..60478f4a9c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -53,6 +53,7 @@ #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #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") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") #if defined(TARGET_RISCV32) diff --git a/target/riscv/cpu_vendorid.h b/target/riscv/cpu_vendorid.h new file mode 100644 index 0000000000..a5aa249bc9 --- /dev/null +++ b/target/riscv/cpu_vendorid.h @@ -0,0 +1,6 @@ +#ifndef TARGET_RISCV_CPU_VENDORID_H +#define TARGET_RISCV_CPU_VENDORID_H + +#define THEAD_VENDOR_ID 0x5b7 + +#endif /* TARGET_RISCV_CPU_VENDORID_H */ From 578086ba2ffe4afb24b94975d75dfc02f8be1ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:12 +0100 Subject: [PATCH 595/814] RISC-V: Adding XTheadFmv ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the XTheadFmv ISA extension. The patch uses the T-Head specific decoder and translation. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-14-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu.h | 1 + target/riscv/insn_trans/trans_xthead.c.inc | 45 ++++++++++++++++++++++ target/riscv/translate.c | 6 +-- target/riscv/xthead.decode | 4 ++ 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 8cbc5c9c1b..0dd2f0c753 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -116,6 +116,7 @@ static const struct isa_ext_data isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(xtheadcmo, true, PRIV_VERSION_1_11_0, ext_xtheadcmo), ISA_EXT_DATA_ENTRY(xtheadcondmov, true, PRIV_VERSION_1_11_0, ext_xtheadcondmov), ISA_EXT_DATA_ENTRY(xtheadfmemidx, true, PRIV_VERSION_1_11_0, ext_xtheadfmemidx), + ISA_EXT_DATA_ENTRY(xtheadfmv, true, PRIV_VERSION_1_11_0, ext_xtheadfmv), ISA_EXT_DATA_ENTRY(xtheadmac, true, PRIV_VERSION_1_11_0, ext_xtheadmac), ISA_EXT_DATA_ENTRY(xtheadmemidx, true, PRIV_VERSION_1_11_0, ext_xtheadmemidx), ISA_EXT_DATA_ENTRY(xtheadmempair, true, PRIV_VERSION_1_11_0, ext_xtheadmempair), @@ -1134,6 +1135,7 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_BOOL("xtheadcmo", RISCVCPU, cfg.ext_xtheadcmo, false), DEFINE_PROP_BOOL("xtheadcondmov", RISCVCPU, cfg.ext_xtheadcondmov, false), DEFINE_PROP_BOOL("xtheadfmemidx", RISCVCPU, cfg.ext_xtheadfmemidx, false), + DEFINE_PROP_BOOL("xtheadfmv", RISCVCPU, cfg.ext_xtheadfmv, false), DEFINE_PROP_BOOL("xtheadmac", RISCVCPU, cfg.ext_xtheadmac, false), DEFINE_PROP_BOOL("xtheadmemidx", RISCVCPU, cfg.ext_xtheadmemidx, false), DEFINE_PROP_BOOL("xtheadmempair", RISCVCPU, cfg.ext_xtheadmempair, false), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 60478f4a9c..7128438d8e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -480,6 +480,7 @@ struct RISCVCPUConfig { bool ext_xtheadcmo; bool ext_xtheadcondmov; bool ext_xtheadfmemidx; + bool ext_xtheadfmv; bool ext_xtheadmac; bool ext_xtheadmemidx; bool ext_xtheadmempair; diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 37373732f6..be87c34f56 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -52,6 +52,12 @@ } \ } while (0) +#define REQUIRE_XTHEADFMV(ctx) do { \ + if (!ctx->cfg_ptr->ext_xtheadfmv) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XTHEADMAC(ctx) do { \ if (!ctx->cfg_ptr->ext_xtheadmac) { \ return false; \ @@ -449,6 +455,45 @@ static bool trans_th_fsurw(DisasContext *ctx, arg_th_memidx *a) return gen_fstore_idx(ctx, a, MO_TEUL, true); } +/* XTheadFmv */ + +static bool trans_th_fmv_hw_x(DisasContext *ctx, arg_th_fmv_hw_x *a) +{ + REQUIRE_XTHEADFMV(ctx); + REQUIRE_32BIT(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + + TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t1, src1); + tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], t1, 32, 32); + tcg_temp_free_i64(t1); + mark_fs_dirty(ctx); + return true; +} + +static bool trans_th_fmv_x_hw(DisasContext *ctx, arg_th_fmv_x_hw *a) +{ + REQUIRE_XTHEADFMV(ctx); + REQUIRE_32BIT(ctx); + REQUIRE_FPU; + REQUIRE_EXT(ctx, RVD); + TCGv dst; + TCGv_i64 t1; + + dst = dest_gpr(ctx, a->rd); + t1 = tcg_temp_new_i64(); + + tcg_gen_extract_i64(t1, cpu_fpr[a->rs1], 32, 32); + tcg_gen_trunc_i64_tl(dst, t1); + gen_set_gpr(ctx, a->rd, dst); + tcg_temp_free_i64(t1); + mark_fs_dirty(ctx); + return true; +} + /* XTheadMac */ static bool gen_th_mac(DisasContext *ctx, arg_r *a, diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 216eaf9d12..182649dcb6 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -135,9 +135,9 @@ static bool has_xthead_p(DisasContext *ctx __attribute__((__unused__))) return ctx->cfg_ptr->ext_xtheadba || ctx->cfg_ptr->ext_xtheadbb || ctx->cfg_ptr->ext_xtheadbs || ctx->cfg_ptr->ext_xtheadcmo || ctx->cfg_ptr->ext_xtheadcondmov || - ctx->cfg_ptr->ext_xtheadfmemidx || ctx->cfg_ptr->ext_xtheadmac || - ctx->cfg_ptr->ext_xtheadmemidx || ctx->cfg_ptr->ext_xtheadmempair || - ctx->cfg_ptr->ext_xtheadsync; + ctx->cfg_ptr->ext_xtheadfmemidx || ctx->cfg_ptr->ext_xtheadfmv || + ctx->cfg_ptr->ext_xtheadmac || ctx->cfg_ptr->ext_xtheadmemidx || + ctx->cfg_ptr->ext_xtheadmempair || ctx->cfg_ptr->ext_xtheadsync; } #define MATERIALISE_EXT_PREDICATE(ext) \ diff --git a/target/riscv/xthead.decode b/target/riscv/xthead.decode index 81daf1d694..d1d104bcf2 100644 --- a/target/riscv/xthead.decode +++ b/target/riscv/xthead.decode @@ -110,6 +110,10 @@ th_fsrw 01000 .. ..... ..... 111 ..... 0001011 @th_memidx th_fsurd 01110 .. ..... ..... 111 ..... 0001011 @th_memidx th_fsurw 01010 .. ..... ..... 111 ..... 0001011 @th_memidx +# XTheadFmv +th_fmv_hw_x 1010000 00000 ..... 001 ..... 0001011 @r2 +th_fmv_x_hw 1100000 00000 ..... 001 ..... 0001011 @r2 + # XTheadMac th_mula 00100 00 ..... ..... 001 ..... 0001011 @r th_mulah 00101 00 ..... ..... 001 ..... 0001011 @r From 179d9e2911f26088360a1d663767cf6612f96f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Tue, 31 Jan 2023 21:20:13 +0100 Subject: [PATCH 596/814] target/riscv: add a MAINTAINERS entry for XThead* extension support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XThead* extensions are maintained by T-Head and VRULL. Adding a point of contact from both companies. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-Id: <20230131202013.2541053-15-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fa10ecaeb9..96e25f62ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -295,6 +295,14 @@ F: include/hw/riscv/ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ +RISC-V XThead* extensions +M: Christoph Muellner +M: LIU Zhiwei +L: qemu-riscv@nongnu.org +S: Supported +F: target/riscv/insn_trans/trans_xthead.c.inc +F: target/riscv/xthead*.decode + RISC-V XVentanaCondOps extension M: Philipp Tomsich L: qemu-riscv@nongnu.org From 506c6698fbe53e88fba3160fc3842e5d41a9ee25 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 27 Jan 2023 11:17:58 -0800 Subject: [PATCH 597/814] target/riscv: fix for virtual instr exception commit fb3f3730e4 added mechanism to generate virtual instruction exception during instruction decode when virt is enabled. However in some situations, illegal instruction exception can be raised due to state of CPU. One such situation is implementing branch tracking. [1] An indirect branch if doesn't land on a landing pad instruction, then cpu must raise an illegal instruction exception. Implementation would raise such expcetion due to missing landing pad inst and not due to decode. Thus DisasContext must have `virt_inst_excp` initialized to false during DisasContxt initialization for TB. [1] - https://github.com/riscv/riscv-cfi Signed-off-by: Deepak Gupta Reviewed-by: Alistair Francis Message-Id: <20230127191758.755844-1-debug@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 182649dcb6..772f9d7973 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1213,6 +1213,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED); ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER); ctx->zero = tcg_constant_tl(0); + ctx->virt_inst_excp = false; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) From 5fc0fc8788e08f151f5d0c47d205e009aeb33844 Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Sat, 4 Feb 2023 11:23:12 +0300 Subject: [PATCH 598/814] target/riscv: fix ctzw behavior According to spec, ctzw should work with 32-bit register, not 64. For example, previous implementation returns 33 for (1<<33) input when the new one returns 32. Signed-off-by: Vladimir Isaev Reviewed-by: Alistair Francis Suggested-by: Richard Henderson Message-Id: <20230204082312.43557-1-vladimir.isaev@syntacore.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvb.c.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc index e2b8329f1e..990bc94b98 100644 --- a/target/riscv/insn_trans/trans_rvb.c.inc +++ b/target/riscv/insn_trans/trans_rvb.c.inc @@ -401,6 +401,7 @@ static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); + ctx->ol = MXL_RV32; return gen_unary(ctx, a, EXT_ZERO, gen_ctzw); } From 947bf7fe9f0831cb6944334a06ff0b84926612b8 Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Fri, 3 Feb 2023 16:51:55 +0300 Subject: [PATCH 599/814] target/riscv: fix SBI getchar handler for KVM Character must be returned via ret[0] field (copied to a0 by KVM). Return value should be set to 0 to indicate successful processing. Signed-off-by: Vladimir Isaev Reviewed-by: Alistair Francis Message-Id: <20230203135155.12449-1-vladimir.isaev@syntacore.com> Signed-off-by: Alistair Francis --- target/riscv/kvm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c index 30f21453d6..0f932a5b96 100644 --- a/target/riscv/kvm.c +++ b/target/riscv/kvm.c @@ -467,10 +467,11 @@ static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) case SBI_EXT_0_1_CONSOLE_GETCHAR: ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch)); if (ret == sizeof(ch)) { - run->riscv_sbi.args[0] = ch; + run->riscv_sbi.ret[0] = ch; } else { - run->riscv_sbi.args[0] = -1; + run->riscv_sbi.ret[0] = -1; } + ret = 0; break; default: qemu_log_mask(LOG_UNIMP, From 5474aa4f3e0a3e9c171db7c55b5baf15f2e2778c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Feb 2023 16:50:07 +0800 Subject: [PATCH 600/814] hw/riscv: virt: Simplify virt_{get,set}_aclint() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to declare an intermediate "MachineState *ms". Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-Id: <20230206085007.3618715-1-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a061151a6f..b81081c70b 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1583,16 +1583,14 @@ static void virt_set_aia(Object *obj, const char *val, Error **errp) static bool virt_get_aclint(Object *obj, Error **errp) { - MachineState *ms = MACHINE(obj); - RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); return s->have_aclint; } static void virt_set_aclint(Object *obj, bool value, Error **errp) { - MachineState *ms = MACHINE(obj); - RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); s->have_aclint = value; } From ffd0cac708733ec0e039e3aa8a49f371ac066f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 601/814] tests/avocado: Introduce file_truncate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20230120134314.81956-2-philmd@linaro.org [ clg: remove image_pow2ceil_expand() factoring ] Signed-off-by: Cédric Le Goater --- tests/avocado/boot_linux_console.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 8c1d981586..13e6688624 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -30,6 +30,11 @@ Round up to next power of 2 def pow2ceil(x): return 1 if x == 0 else 2**(x - 1).bit_length() +def file_truncate(path, size): + if size != os.path.getsize(path): + with open(path, 'ab+') as fd: + fd.truncate(size) + """ Expand file size to next power of 2 """ From a7f16aed392f0da4e8df134228af0b0bfa56b127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 602/814] tests/avocado: Truncate M2S-FG484 SOM SPI flash to 16MiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The M2S-FG484 SOM uses a 16 MiB SPI flash (Spansion S25FL128SDPBHICO). Since the test asset is bigger, truncate it to the correct size to avoid when running the test_arm_emcraft_sf2 test: qemu-system-arm: device requires 16777216 bytes, block backend provides 67108864 bytes Add comment regarding the M2S-FG484 SOM hardware in hw/arm/msf2-som.c. Reported-by: Cédric Le Goater Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/arm/msf2-som.c | 5 ++++- tests/avocado/boot_linux_console.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index a6df473ec9..7b3106c790 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -1,6 +1,9 @@ /* * SmartFusion2 SOM starter kit(from Emcraft) emulation. * + * M2S-FG484 SOM hardware architecture specification: + * https://www.emcraft.com/jdownloads/som/m2s/m2s-som-ha.pdf + * * Copyright (c) 2017 Subbaraya Sundeep * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -87,7 +90,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine) /* Attach SPI flash to SPI0 controller */ spi_bus = qdev_get_child_bus(dev, "spi0"); - spi_flash = qdev_new("s25sl12801"); + spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */ qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1); if (dinfo) { qdev_prop_set_drive_err(spi_flash, "drive", diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 13e6688624..258f2ee897 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -400,6 +400,8 @@ class BootLinuxConsole(LinuxKernelTest): spi_hash = '65523a1835949b6f4553be96dec1b6a38fb05501' spi_path = self.fetch_asset(spi_url, asset_hash=spi_hash) + file_truncate(spi_path, 16 << 20) # Spansion S25FL128SDPBHICO is 16 MiB + self.vm.set_console() kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE self.vm.add_args('-kernel', uboot_path, From 479365979bdc2fc4f8d2375085c980fe3f520c39 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 603/814] aspeed: Add Supermicro X11 SPI machine type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit supermicrox11-bmc is configured with ast2400-a1 SoC. This does not match the Supermicro documentation for X11 BMCs, and it does not match the devicetree file in the Linux kernel. As it turns out, some Supermicro X11 motherboards use AST2400 SoCs, while others use AST2500. Introduce new machine type supermicrox11-spi-bmc with AST2500 SoC to match the devicetree description in the Linux kernel. Hardware configuration details for this machine type are guesswork and taken from defaults as well as from the Linux kernel devicetree file. The new machine type was tested with aspeed-bmc-supermicro-x11spi.dts from the Linux kernel and with Linux versions 6.0.3 and 6.1-rc2. Linux booted successfully from initrd and from both SPI interfaces. Ethernet interfaces were confirmed to be operational. Signed-off-by: Guenter Roeck Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20221025165109.1226001-1-linux@roeck-us.net [ clg: Renamed machine to 'supermicro-x11spi-bmc' ] Message-Id: <20221025165109.1226001-1-linux@roeck-us.net> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 55f114ef72..0c8c3be413 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -71,6 +71,16 @@ struct AspeedMachineState { SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) +/* TODO: Find the actual hardware value */ +#define SUPERMICRO_X11SPI_BMC_HW_STRAP1 ( \ + AST2500_HW_STRAP1_DEFAULTS | \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_HW_STRAP_SPI_WIDTH | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN)) + /* AST2500 evb hardware value: 0xF100C2E6 */ #define AST2500_EVB_HW_STRAP1 (( \ AST2500_HW_STRAP1_DEFAULTS | \ @@ -1141,6 +1151,25 @@ static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, mc->default_ram_size = 256 * MiB; } +static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, + void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Supermicro X11 SPI BMC (ARM1176)"; + amc->soc_name = "ast2500-a1"; + amc->hw_strap1 = SUPERMICRO_X11SPI_BMC_HW_STRAP1; + amc->fmc_model = "mx25l25635e"; + amc->spi_model = "mx25l25635e"; + amc->num_cs = 1; + amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; + amc->i2c_init = palmetto_bmc_i2c_init; + mc->default_ram_size = 512 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); +} + static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1522,6 +1551,10 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("supermicrox11-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_supermicrox11_bmc_class_init, + }, { + .name = MACHINE_TYPE_NAME("supermicro-x11spi-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_supermicro_x11spi_bmc_class_init, }, { .name = MACHINE_TYPE_NAME("ast2500-evb"), .parent = TYPE_ASPEED_MACHINE, From 036e98e5c2b4e25c8d6ccbddb85c7ab05a753f6a Mon Sep 17 00:00:00 2001 From: Stephen Longfield Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 604/814] hw/net: Fix read of uninitialized memory in ftgmac100 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the `size += 4` before the call to `crc32`, the CRC calculation would overrun the buffer. Size is used in the while loop starting on line 1009 to determine how much data to write back, with the last four bytes coming from `crc_ptr`, so do need to increase it, but should do this after the computation. I'm unsure why this use of uninitialized memory in the CRC doesn't result in CRC errors, but it seems clear to me that it should not be included in the calculation. Signed-off-by: Stephen Longfield Reviewed-by: Hao Wu Reviewed-by: Joel Stanley Message-Id: <20221220221437.3303721-1-slongfield@google.com> Signed-off-by: Cédric Le Goater --- hw/net/ftgmac100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 83ef0a783e..d3bf14be53 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -980,9 +980,9 @@ static ssize_t ftgmac100_receive(NetClientState *nc, const uint8_t *buf, return size; } - /* 4 bytes for the CRC. */ - size += 4; crc = cpu_to_be32(crc32(~0, buf, size)); + /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */ + size += 4; crc_ptr = (uint8_t *) &crc; /* Huge frames are truncated. */ From 9b983dc78b273985ad51a1a929dd0e4e98ddb39e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 605/814] avocado/boot_linux_console.py: Update ast2600 test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the test_arm_ast2600_debian test to - the latest Debian kernel - use the Rainier machine instead of Tacoma Both of which contains support for more hardware and thus exercises more of the hardware Qemu models. Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Message-Id: <20220607011938.1676459-1-joel@jms.id.au> Signed-off-by: Cédric Le Goater --- tests/avocado/boot_linux_console.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 258f2ee897..be60f8cda9 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -1105,18 +1105,18 @@ class BootLinuxConsole(LinuxKernelTest): def test_arm_ast2600_debian(self): """ :avocado: tags=arch:arm - :avocado: tags=machine:tacoma-bmc + :avocado: tags=machine:rainier-bmc """ deb_url = ('http://snapshot.debian.org/archive/debian/' - '20210302T203551Z/' + '20220606T211338Z/' 'pool/main/l/linux/' - 'linux-image-5.10.0-3-armmp_5.10.13-1_armhf.deb') - deb_hash = 'db40d32fe39255d05482bea48d72467b67d6225bb2a2a4d6f618cb8976f1e09e' + 'linux-image-5.17.0-2-armmp_5.17.6-1%2Bb1_armhf.deb') + deb_hash = '8acb2b4439faedc2f3ed4bdb2847ad4f6e0491f73debaeb7f660c8abe4dcdc0e' deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash, algorithm='sha256') - kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.10.0-3-armmp') + kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.17.0-2-armmp') dtb_path = self.extract_from_deb(deb_path, - '/usr/lib/linux-image-5.10.0-3-armmp/aspeed-bmc-opp-tacoma.dtb') + '/usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb') self.vm.set_console() self.vm.add_args('-kernel', kernel_path, From 3e7808de0537a630520e7c7a2d8291e85289dbb4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 606/814] m25p80: Add the is25wp256 SFPD table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated from hardware using the following command and then padding with 0xff to fill out a power-of-2: xxd -p /sys/bus/spi/devices/spi0.0/spi-nor/sfdp Cc: Michael Walle Cc: Tudor Ambarus Signed-off-by: Guenter Roeck Reviewed-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-Id: <20221221122213.1458540-1-linux@roeck-us.net> Signed-off-by: Cédric Le Goater --- hw/block/m25p80.c | 3 ++- hw/block/m25p80_sfdp.c | 40 ++++++++++++++++++++++++++++++++++++++++ hw/block/m25p80_sfdp.h | 2 ++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 02adc87527..802d2eb021 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -221,7 +221,8 @@ static const FlashPartInfo known_devices[] = { { INFO("is25wp032", 0x9d7016, 0, 64 << 10, 64, ER_4K) }, { INFO("is25wp064", 0x9d7017, 0, 64 << 10, 128, ER_4K) }, { INFO("is25wp128", 0x9d7018, 0, 64 << 10, 256, ER_4K) }, - { INFO("is25wp256", 0x9d7019, 0, 64 << 10, 512, ER_4K) }, + { INFO("is25wp256", 0x9d7019, 0, 64 << 10, 512, ER_4K), + .sfdp_read = m25p80_sfdp_is25wp256 }, /* Macronix */ { INFO("mx25l2005a", 0xc22012, 0, 64 << 10, 4, ER_4K) }, diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c index 77615fa29e..b33811a4f5 100644 --- a/hw/block/m25p80_sfdp.c +++ b/hw/block/m25p80_sfdp.c @@ -330,3 +330,43 @@ static const uint8_t sfdp_w25q01jvq[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; define_sfdp_read(w25q01jvq); + +/* + * Integrated Silicon Solution (ISSI) + */ + +static const uint8_t sfdp_is25wp256[] = { + 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff, + 0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff, + 0x9d, 0x05, 0x01, 0x03, 0x80, 0x00, 0x00, 0x02, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x20, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x80, 0xbb, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x44, 0xeb, 0x0c, 0x20, 0x0f, 0x52, + 0x10, 0xd8, 0x00, 0xff, 0x23, 0x4a, 0xc9, 0x00, + 0x82, 0xd8, 0x11, 0xce, 0xcc, 0xcd, 0x68, 0x46, + 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xae, 0xd5, 0x5c, + 0x4a, 0x42, 0x2c, 0xff, 0xf0, 0x30, 0xfa, 0xa9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x50, 0x19, 0x50, 0x16, 0x9f, 0xf9, 0xc0, 0x64, + 0x8f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +define_sfdp_read(is25wp256); diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h index df7adfb5ce..011a880f66 100644 --- a/hw/block/m25p80_sfdp.h +++ b/hw/block/m25p80_sfdp.h @@ -26,4 +26,6 @@ uint8_t m25p80_sfdp_w25q512jv(uint32_t addr); uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr); +uint8_t m25p80_sfdp_is25wp256(uint32_t addr); + #endif From ed1f5ff84209202de90ad7c3a7e51478353234ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 607/814] tests/avocado/machine_aspeed.py: update buildroot tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use buildroot 2022.11 based images plus some customization : - Linux version is bumped to 6.0.9 and kernel is built with a custom config similar to what OpenBMC provides. - U-Boot is switched to the one provided by OpenBMC for better support. - defconfigs includes more target tools for dev. Reviewed-by: Joel Stanley Message-Id: <20230119123449.531826-7-clg@kaod.org> Signed-off-by: Cédric Le Goater --- tests/avocado/machine_aspeed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index 1fc385e1c8..773b1ff3a9 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -123,8 +123,8 @@ class AST2x00Machine(QemuSystemTest): """ image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' - 'images/ast2500-evb/buildroot-2022.05/flash.img') - image_hash = ('549db6e9d8cdaf4367af21c36385a68bb465779c18b5e37094fc7343decccd3f') + 'images/ast2500-evb/buildroot-2022.11-2-g15d3648df9/flash.img') + image_hash = ('f96d11db521fe7a2787745e9e391225deeeec3318ee0fc07c8b799b8833dd474') image_path = self.fetch_asset(image_url, asset_hash=image_hash, algorithm='sha256') @@ -151,8 +151,8 @@ class AST2x00Machine(QemuSystemTest): """ image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/' - 'images/ast2600-evb/buildroot-2022.05/flash.img') - image_hash = ('6cc9e7d128fd4fa1fd01c883af67593cae8072c3239a0b8b6ace857f3538a92d') + 'images/ast2600-evb/buildroot-2022.11-2-g15d3648df9/flash.img') + image_hash = ('e598d86e5ea79671ca8b59212a326c911bc8bea728dec1a1f5390d717a28bb8b') image_path = self.fetch_asset(image_url, asset_hash=image_hash, algorithm='sha256') From 30d7aac415bc4b6d859759cb0b68a2d46b251450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 608/814] tests/avocado/machine_aspeed.py: Mask systemd services to speed up SDK boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Joel Stanley Message-Id: <20230119123449.531826-8-clg@kaod.org> Signed-off-by: Cédric Le Goater --- tests/avocado/machine_aspeed.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index 773b1ff3a9..1cab946727 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -183,7 +183,14 @@ class AST2x00Machine(QemuSystemTest): class AST2x00MachineSDK(QemuSystemTest): - EXTRA_BOOTARGS = ' quiet' + EXTRA_BOOTARGS = ( + 'quiet ' + 'systemd.mask=org.openbmc.HostIpmi.service ' + 'systemd.mask=xyz.openbmc_project.Chassis.Control.Power@0.service ' + 'systemd.mask=modprobe@fuse.service ' + 'systemd.mask=rngd.service ' + 'systemd.mask=obmc-console@ttyS2.service ' + ) # FIXME: Although these tests boot a whole distro they are still # slower than comparable machine models. There may be some @@ -208,7 +215,7 @@ class AST2x00MachineSDK(QemuSystemTest): interrupt_interactive_console_until_pattern( self, 'Hit any key to stop autoboot:', 'ast#') exec_command_and_wait_for_pattern( - self, 'setenv bootargs ${bootargs}' + self.EXTRA_BOOTARGS, 'ast#') + self, 'setenv bootargs ${bootargs} ' + self.EXTRA_BOOTARGS, 'ast#') exec_command_and_wait_for_pattern( self, 'boot', '## Loading kernel from FIT Image') self.wait_for_console_pattern('Starting kernel ...') From ddbf7bd73c9c79dc48f5981100876242df533d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 609/814] hw/core/loader: Remove declarations of option_rom_has_mr/rom_file_has_mr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These globals were moved to MachineClass by commit 71ae9e94d9 ("pc: Move option_rom_has_mr/rom_file_has_mr globals to MachineClass"). Finish cleanup. Cc: Eduardo Habkost Cc: Marcel Apfelbaum Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Joel Stanley Signed-off-by: Cédric Le Goater --- include/hw/loader.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/hw/loader.h b/include/hw/loader.h index 70248e0da7..1384796a4b 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -251,9 +251,6 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source); -extern bool option_rom_has_mr; -extern bool rom_file_has_mr; - ssize_t rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, bool option_rom, MemoryRegion *mr, AddressSpace *as); From 9618ebae453f2492a60e741d40f5212103f48ad3 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 610/814] hw/arm: Extract at24c_eeprom_init helper from Aspeed and Nuvoton boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helper is useful in board initialization because lets users initialize and realize an EEPROM on an I2C bus with a single function call. Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Reviewed-by: Joel Stanley Reviewed-by: Corey Minyard Link: https://lore.kernel.org/r/20230128060543.95582-2-peter@pjd.dev Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 10 +--------- hw/arm/npcm7xx_boards.c | 20 +++++--------------- hw/nvram/eeprom_at24c.c | 12 ++++++++++++ include/hw/nvram/eeprom_at24c.h | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 include/hw/nvram/eeprom_at24c.h diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 0c8c3be413..8a84249525 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -17,6 +17,7 @@ #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/misc/pca9552.h" +#include "hw/nvram/eeprom_at24c.h" #include "hw/sensor/tmp105.h" #include "hw/misc/led.h" #include "hw/qdev-properties.h" @@ -439,15 +440,6 @@ static void aspeed_machine_init(MachineState *machine) arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); } -static void at24c_eeprom_init(I2CBus *bus, uint8_t addr, uint32_t rsize) -{ - I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr); - DeviceState *dev = DEVICE(i2c_dev); - - qdev_prop_set_uint32(dev, "rom-size", rsize); - i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); -} - static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 6bc6f5d2fe..9b31207a06 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -21,6 +21,7 @@ #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/loader.h" +#include "hw/nvram/eeprom_at24c.h" #include "hw/qdev-core.h" #include "hw/qdev-properties.h" #include "qapi/error.h" @@ -140,17 +141,6 @@ static I2CBus *npcm7xx_i2c_get_bus(NPCM7xxState *soc, uint32_t num) return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus")); } -static void at24c_eeprom_init(NPCM7xxState *soc, int bus, uint8_t addr, - uint32_t rsize) -{ - I2CBus *i2c_bus = npcm7xx_i2c_get_bus(soc, bus); - I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr); - DeviceState *dev = DEVICE(i2c_dev); - - qdev_prop_set_uint32(dev, "rom-size", rsize); - i2c_slave_realize_and_unref(i2c_dev, i2c_bus, &error_abort); -} - static void npcm7xx_init_pwm_splitter(NPCM7xxMachine *machine, NPCM7xxState *soc, const int *fan_counts) { @@ -253,8 +243,8 @@ static void quanta_gsj_i2c_init(NPCM7xxState *soc) i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 3), "tmp105", 0x5c); i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 4), "tmp105", 0x5c); - at24c_eeprom_init(soc, 9, 0x55, 8192); - at24c_eeprom_init(soc, 10, 0x55, 8192); + at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 9), 0x55, 8192); + at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 10), 0x55, 8192); /* * i2c-11: @@ -360,7 +350,7 @@ static void kudo_bmc_i2c_init(NPCM7xxState *soc) i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 4), TYPE_PCA9548, 0x77); - at24c_eeprom_init(soc, 4, 0x50, 8192); /* mbfru */ + at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 4), 0x50, 8192); /* mbfru */ i2c_mux = i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 13), TYPE_PCA9548, 0x77); @@ -371,7 +361,7 @@ static void kudo_bmc_i2c_init(NPCM7xxState *soc) i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 4), "tmp105", 0x48); i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 5), "tmp105", 0x49); - at24c_eeprom_init(soc, 14, 0x55, 8192); /* bmcfru */ + at24c_eeprom_init(npcm7xx_i2c_get_bus(soc, 14), 0x55, 8192); /* bmcfru */ /* TODO: Add remaining i2c devices. */ } diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index 2d4d8b952f..98857e3626 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -12,6 +12,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "hw/i2c/i2c.h" +#include "hw/nvram/eeprom_at24c.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "sysemu/block-backend.h" @@ -128,6 +129,17 @@ int at24c_eeprom_send(I2CSlave *s, uint8_t data) return 0; } +I2CSlave *at24c_eeprom_init(I2CBus *bus, uint8_t address, uint32_t rom_size) +{ + I2CSlave *i2c_dev = i2c_slave_new(TYPE_AT24C_EE, address); + DeviceState *dev = DEVICE(i2c_dev); + + qdev_prop_set_uint32(dev, "rom-size", rom_size); + i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); + + return i2c_dev; +} + static void at24c_eeprom_realize(DeviceState *dev, Error **errp) { EEPROMState *ee = AT24C_EE(dev); diff --git a/include/hw/nvram/eeprom_at24c.h b/include/hw/nvram/eeprom_at24c.h new file mode 100644 index 0000000000..196db309d4 --- /dev/null +++ b/include/hw/nvram/eeprom_at24c.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef EEPROM_AT24C_H +#define EEPROM_AT24C_H + +#include "hw/i2c/i2c.h" + +/* + * Create and realize an AT24C EEPROM device on the heap. + * @bus: I2C bus to put it on + * @address: I2C address of the EEPROM slave when put on a bus + * @rom_size: size of the EEPROM + * + * Create the device state structure, initialize it, put it on the specified + * @bus, and drop the reference to it (the device is realized). + */ +I2CSlave *at24c_eeprom_init(I2CBus *bus, uint8_t address, uint32_t rom_size); + +#endif From 9077e09a13755b4774a4e640ed3ac1a92db11839 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 611/814] hw/arm/aspeed: Replace aspeed_eeprom_init with at24c_eeprom_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aspeed_eeprom_init is an exact copy of at24c_eeprom_init, not needed. Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Joel Stanley Reviewed-by: Corey Minyard Link: https://lore.kernel.org/r/20230128060543.95582-3-peter@pjd.dev Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 95 ++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 8a84249525..ed2268e1dd 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -670,15 +670,6 @@ static void g220a_bmc_i2c_init(AspeedMachineState *bmc) eeprom_buf); } -static void aspeed_eeprom_init(I2CBus *bus, uint8_t addr, uint32_t rsize) -{ - I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr); - DeviceState *dev = DEVICE(i2c_dev); - - qdev_prop_set_uint32(dev, "rom-size", rsize); - i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); -} - static void fp5280g2_bmc_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -711,7 +702,7 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) AspeedSoCState *soc = &bmc->soc; I2CSlave *i2c_mux; - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 0), 0x51, 32 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 0), 0x51, 32 * KiB); create_pca9552(soc, 3, 0x61); @@ -724,9 +715,9 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) 0x4a); i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "pca9546", 0x70); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x52, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x52, 64 * KiB); create_pca9552(soc, 4, 0x60); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105, @@ -737,8 +728,8 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) create_pca9552(soc, 5, 0x61); i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), "pca9546", 0x70); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, 0x48); @@ -748,10 +739,10 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) 0x4b); i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), "pca9546", 0x70); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x50, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 3), 0x51, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 2), 0x50, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 3), 0x51, 64 * KiB); create_pca9552(soc, 7, 0x30); create_pca9552(soc, 7, 0x31); @@ -764,15 +755,15 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, 0x48); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "max31785", 0x52); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, 64 * KiB); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x51, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x50, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 7), 0x51, 64 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, 0x48); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, 0x4a); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x50, 64 * KiB); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x51, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x50, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 8), 0x51, 64 * KiB); create_pca9552(soc, 8, 0x60); create_pca9552(soc, 8, 0x61); /* Bus 8: ucd90320@11 */ @@ -781,11 +772,11 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4d); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 9), 0x50, 128 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 9), 0x50, 128 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4d); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 10), 0x50, 128 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 10), 0x50, 128 * KiB); i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105, 0x48); @@ -793,18 +784,18 @@ static void rainier_bmc_i2c_init(AspeedMachineState *bmc) 0x49); i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "pca9546", 0x70); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); - aspeed_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 0), 0x50, 64 * KiB); + at24c_eeprom_init(pca954x_i2c_get_bus(i2c_mux, 1), 0x51, 64 * KiB); create_pca9552(soc, 11, 0x60); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 13), 0x50, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 13), 0x50, 64 * KiB); create_pca9552(soc, 13, 0x60); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 14), 0x50, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 14), 0x50, 64 * KiB); create_pca9552(soc, 14, 0x60); - aspeed_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 15), 0x50, 64 * KiB); + at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 15), 0x50, 64 * KiB); create_pca9552(soc, 15, 0x60); } @@ -848,45 +839,45 @@ static void fuji_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[17], TYPE_LM75, 0x4c); i2c_slave_create_simple(i2c[17], TYPE_LM75, 0x4d); - aspeed_eeprom_init(i2c[19], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[20], 0x50, 2 * KiB); - aspeed_eeprom_init(i2c[22], 0x52, 2 * KiB); + at24c_eeprom_init(i2c[19], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[20], 0x50, 2 * KiB); + at24c_eeprom_init(i2c[22], 0x52, 2 * KiB); i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x48); i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x49); i2c_slave_create_simple(i2c[3], TYPE_LM75, 0x4a); i2c_slave_create_simple(i2c[3], TYPE_TMP422, 0x4c); - aspeed_eeprom_init(i2c[8], 0x51, 64 * KiB); + at24c_eeprom_init(i2c[8], 0x51, 64 * KiB); i2c_slave_create_simple(i2c[8], TYPE_LM75, 0x4a); i2c_slave_create_simple(i2c[50], TYPE_LM75, 0x4c); - aspeed_eeprom_init(i2c[50], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[50], 0x52, 64 * KiB); i2c_slave_create_simple(i2c[51], TYPE_TMP75, 0x48); i2c_slave_create_simple(i2c[52], TYPE_TMP75, 0x49); i2c_slave_create_simple(i2c[59], TYPE_TMP75, 0x48); i2c_slave_create_simple(i2c[60], TYPE_TMP75, 0x49); - aspeed_eeprom_init(i2c[65], 0x53, 64 * KiB); + at24c_eeprom_init(i2c[65], 0x53, 64 * KiB); i2c_slave_create_simple(i2c[66], TYPE_TMP75, 0x49); i2c_slave_create_simple(i2c[66], TYPE_TMP75, 0x48); - aspeed_eeprom_init(i2c[68], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[69], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[70], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[71], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[68], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[69], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[70], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[71], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[73], 0x53, 64 * KiB); + at24c_eeprom_init(i2c[73], 0x53, 64 * KiB); i2c_slave_create_simple(i2c[74], TYPE_TMP75, 0x49); i2c_slave_create_simple(i2c[74], TYPE_TMP75, 0x48); - aspeed_eeprom_init(i2c[76], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[77], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[78], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[79], 0x52, 64 * KiB); - aspeed_eeprom_init(i2c[28], 0x50, 2 * KiB); + at24c_eeprom_init(i2c[76], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[77], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[78], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[79], 0x52, 64 * KiB); + at24c_eeprom_init(i2c[28], 0x50, 2 * KiB); for (int i = 0; i < 8; i++) { - aspeed_eeprom_init(i2c[81 + i * 8], 0x56, 64 * KiB); + at24c_eeprom_init(i2c[81 + i * 8], 0x56, 64 * KiB); i2c_slave_create_simple(i2c[82 + i * 8], TYPE_TMP75, 0x48); i2c_slave_create_simple(i2c[83 + i * 8], TYPE_TMP75, 0x4b); i2c_slave_create_simple(i2c[84 + i * 8], TYPE_TMP75, 0x4a); @@ -957,11 +948,11 @@ static void fby35_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4e); i2c_slave_create_simple(i2c[12], TYPE_LM75, 0x4f); - aspeed_eeprom_init(i2c[4], 0x51, 128 * KiB); - aspeed_eeprom_init(i2c[6], 0x51, 128 * KiB); - aspeed_eeprom_init(i2c[8], 0x50, 32 * KiB); - aspeed_eeprom_init(i2c[11], 0x51, 128 * KiB); - aspeed_eeprom_init(i2c[11], 0x54, 128 * KiB); + at24c_eeprom_init(i2c[4], 0x51, 128 * KiB); + at24c_eeprom_init(i2c[6], 0x51, 128 * KiB); + at24c_eeprom_init(i2c[8], 0x50, 32 * KiB); + at24c_eeprom_init(i2c[11], 0x51, 128 * KiB); + at24c_eeprom_init(i2c[11], 0x54, 128 * KiB); /* * TODO: There is a multi-master i2c connection to an AST1030 MiniBMC on From 9f782e9e827b35166d50476ab26c1b5d568e9509 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 7 Feb 2023 09:02:04 +0100 Subject: [PATCH 612/814] hw/nvram/eeprom_at24c: Add init_rom field and at24c_eeprom_init_rom helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows users to specify binary data to initialize an EEPROM, allowing users to emulate data programmed at manufacturing time. - Added init_rom and init_rom_size attributes to TYPE_AT24C_EE - Added at24c_eeprom_init_rom helper function to initialize attributes - If -drive property is provided, it overrides init_rom data Signed-off-by: Peter Delevoryas Reviewed-by: Joel Stanley Reviewed-by: Corey Minyard Reviewed-by: Cédric Le Goater Tested-by: Ninad Palsule Link: https://lore.kernel.org/r/20230128060543.95582-4-peter@pjd.dev Signed-off-by: Cédric Le Goater --- hw/nvram/eeprom_at24c.c | 36 ++++++++++++++++++++++++++++----- include/hw/nvram/eeprom_at24c.h | 16 +++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index 98857e3626..05598699dc 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -50,6 +50,9 @@ struct EEPROMState { uint8_t *mem; BlockBackend *blk; + + const uint8_t *init_rom; + uint32_t init_rom_size; }; static @@ -131,19 +134,37 @@ int at24c_eeprom_send(I2CSlave *s, uint8_t data) I2CSlave *at24c_eeprom_init(I2CBus *bus, uint8_t address, uint32_t rom_size) { - I2CSlave *i2c_dev = i2c_slave_new(TYPE_AT24C_EE, address); - DeviceState *dev = DEVICE(i2c_dev); + return at24c_eeprom_init_rom(bus, address, rom_size, NULL, 0); +} - qdev_prop_set_uint32(dev, "rom-size", rom_size); - i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort); +I2CSlave *at24c_eeprom_init_rom(I2CBus *bus, uint8_t address, uint32_t rom_size, + const uint8_t *init_rom, uint32_t init_rom_size) +{ + EEPROMState *s; - return i2c_dev; + s = AT24C_EE(i2c_slave_new(TYPE_AT24C_EE, address)); + + qdev_prop_set_uint32(DEVICE(s), "rom-size", rom_size); + + /* TODO: Model init_rom with QOM properties. */ + s->init_rom = init_rom; + s->init_rom_size = init_rom_size; + + i2c_slave_realize_and_unref(I2C_SLAVE(s), bus, &error_abort); + + return I2C_SLAVE(s); } static void at24c_eeprom_realize(DeviceState *dev, Error **errp) { EEPROMState *ee = AT24C_EE(dev); + if (ee->init_rom_size > ee->rsize) { + error_setg(errp, "%s: init rom is larger than rom: %u > %u", + TYPE_AT24C_EE, ee->init_rom_size, ee->rsize); + return; + } + if (ee->blk) { int64_t len = blk_getlength(ee->blk); @@ -163,6 +184,7 @@ static void at24c_eeprom_realize(DeviceState *dev, Error **errp) } ee->mem = g_malloc0(ee->rsize); + } static @@ -176,6 +198,10 @@ void at24c_eeprom_reset(DeviceState *state) memset(ee->mem, 0, ee->rsize); + if (ee->init_rom) { + memcpy(ee->mem, ee->init_rom, MIN(ee->init_rom_size, ee->rsize)); + } + if (ee->blk) { int ret = blk_pread(ee->blk, 0, ee->rsize, ee->mem, 0); diff --git a/include/hw/nvram/eeprom_at24c.h b/include/hw/nvram/eeprom_at24c.h index 196db309d4..acb9857b2a 100644 --- a/include/hw/nvram/eeprom_at24c.h +++ b/include/hw/nvram/eeprom_at24c.h @@ -20,4 +20,20 @@ */ I2CSlave *at24c_eeprom_init(I2CBus *bus, uint8_t address, uint32_t rom_size); + +/* + * Create and realize an AT24C EEPROM device on the heap with initial data. + * @bus: I2C bus to put it on + * @address: I2C address of the EEPROM slave when put on a bus + * @rom_size: size of the EEPROM + * @init_rom: Array of bytes to initialize EEPROM memory with + * @init_rom_size: Size of @init_rom, must be less than or equal to @rom_size + * + * Create the device state structure, initialize it, put it on the specified + * @bus, and drop the reference to it (the device is realized). Copies the data + * from @init_rom to the beginning of the EEPROM memory buffer. + */ +I2CSlave *at24c_eeprom_init_rom(I2CBus *bus, uint8_t address, uint32_t rom_size, + const uint8_t *init_rom, uint32_t init_rom_size); + #endif From c0216b94ed9467c307f5c0cedfc87e5de666b08e Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 613/814] hw/arm/aspeed: Add aspeed_eeprom.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create aspeed_eeprom.c and aspeed_eeprom.h - Include aspeed_eeprom.c in CONFIG_ASPEED meson source files - Include aspeed_eeprom.h in aspeed.c - Add fby35_bmc_fruid data - Use new at24c_eeprom_init_rom helper to initialize BMC FRUID EEPROM with data from aspeed_eeprom.c wget https://github.com/facebook/openbmc/releases/download/openbmc-e2294ff5d31d/fby35.mtd qemu-system-aarch64 -machine fby35-bmc -nographic -mtdblock fby35.mtd ... user: root pass: 0penBmc ... root@bmc-oob:~# fruid-util bb FRU Information : Baseboard --------------- : ------------------ Chassis Type : Rack Mount Chassis Chassis Part Number : N/A Chassis Serial Number : N/A Board Mfg Date : Fri Jan 7 10:30:00 2022 Board Mfg : XXXXXX Board Product : Management Board wBMC Board Serial : XXXXXXXXXXXXX Board Part Number : XXXXXXXXXXXXXX Board FRU ID : 1.0 Board Custom Data 1 : XXXXXXXXX Board Custom Data 2 : XXXXXXXXXXXXXXXXXX Product Manufacturer : XXXXXX Product Name : Yosemite V3.5 EVT2 Product Part Number : XXXXXXXXXXXXXX Product Version : EVT2 Product Serial : XXXXXXXXXXXXX Product Asset Tag : XXXXXXX Product FRU ID : 1.0 Product Custom Data 1 : XXXXXXXXX Product Custom Data 2 : N/A root@bmc-oob:~# fruid-util bmc FRU Information : BMC --------------- : ------------------ Board Mfg Date : Mon Jan 10 21:42:00 2022 Board Mfg : XXXXXX Board Product : BMC Storage Module Board Serial : XXXXXXXXXXXXX Board Part Number : XXXXXXXXXXXXXX Board FRU ID : 1.0 Board Custom Data 1 : XXXXXXXXX Board Custom Data 2 : XXXXXXXXXXXXXXXXXX Product Manufacturer : XXXXXX Product Name : Yosemite V3.5 EVT2 Product Part Number : XXXXXXXXXXXXXX Product Version : EVT2 Product Serial : XXXXXXXXXXXXX Product Asset Tag : XXXXXXX Product FRU ID : 1.0 Product Custom Data 1 : XXXXXXXXX Product Custom Data 2 : Config A root@bmc-oob:~# fruid-util nic FRU Information : NIC --------------- : ------------------ Board Mfg Date : Tue Nov 2 08:51:00 2021 Board Mfg : XXXXXXXX Board Product : Mellanox ConnectX-6 DX OCP3.0 Board Serial : XXXXXXXXXXXXXXXXXXXXXXXX Board Part Number : XXXXXXXXXXXXXXXXXXXXX Board FRU ID : FRU Ver 0.02 Product Manufacturer : XXXXXXXX Product Name : Mellanox ConnectX-6 DX OCP3.0 Product Part Number : XXXXXXXXXXXXXXXXXXXXX Product Version : A9 Product Serial : XXXXXXXXXXXXXXXXXXXXXXXX Product Custom Data 3 : ConnectX-6 DX Signed-off-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Reviewed-by: Joel Stanley Reviewed-by: Corey Minyard Link: https://lore.kernel.org/r/20230128060543.95582-5-peter@pjd.dev Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 10 ++++-- hw/arm/aspeed_eeprom.c | 82 ++++++++++++++++++++++++++++++++++++++++++ hw/arm/aspeed_eeprom.h | 19 ++++++++++ hw/arm/meson.build | 1 + 4 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 hw/arm/aspeed_eeprom.c create mode 100644 hw/arm/aspeed_eeprom.h diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index ed2268e1dd..27dda58338 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -14,6 +14,7 @@ #include "hw/arm/boot.h" #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" +#include "hw/arm/aspeed_eeprom.h" #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/misc/pca9552.h" @@ -950,9 +951,12 @@ static void fby35_i2c_init(AspeedMachineState *bmc) at24c_eeprom_init(i2c[4], 0x51, 128 * KiB); at24c_eeprom_init(i2c[6], 0x51, 128 * KiB); - at24c_eeprom_init(i2c[8], 0x50, 32 * KiB); - at24c_eeprom_init(i2c[11], 0x51, 128 * KiB); - at24c_eeprom_init(i2c[11], 0x54, 128 * KiB); + at24c_eeprom_init_rom(i2c[8], 0x50, 32 * KiB, fby35_nic_fruid, + fby35_nic_fruid_len); + at24c_eeprom_init_rom(i2c[11], 0x51, 128 * KiB, fby35_bb_fruid, + fby35_bb_fruid_len); + at24c_eeprom_init_rom(i2c[11], 0x54, 128 * KiB, fby35_bmc_fruid, + fby35_bmc_fruid_len); /* * TODO: There is a multi-master i2c connection to an AST1030 MiniBMC on diff --git a/hw/arm/aspeed_eeprom.c b/hw/arm/aspeed_eeprom.c new file mode 100644 index 0000000000..04463acc9d --- /dev/null +++ b/hw/arm/aspeed_eeprom.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include "aspeed_eeprom.h" + +const uint8_t fby35_nic_fruid[] = { + 0x01, 0x00, 0x00, 0x01, 0x0f, 0x20, 0x00, 0xcf, 0x01, 0x0e, 0x19, 0xd7, + 0x5e, 0xcf, 0xc8, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xdd, + 0x4d, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x6f, 0x78, 0x20, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x58, 0x2d, 0x36, 0x20, 0x44, 0x58, 0x20, 0x4f, + 0x43, 0x50, 0x33, 0x2e, 0x30, 0xd8, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd5, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0xcc, 0x46, 0x52, 0x55, 0x20, 0x56, 0x65, 0x72, + 0x20, 0x30, 0x2e, 0x30, 0x32, 0xc0, 0xc0, 0xc0, 0xc1, 0x00, 0x00, 0x2f, + 0x01, 0x11, 0x19, 0xc8, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0xdd, 0x4d, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x6f, 0x78, 0x20, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x58, 0x2d, 0x36, 0x20, 0x44, 0x58, 0x20, + 0x4f, 0x43, 0x50, 0x33, 0x2e, 0x30, 0xd5, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0xd3, 0x41, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0xd8, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0xc0, 0xc0, 0xc0, 0xc0, 0xcd, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x58, 0x2d, 0x36, 0x20, 0x44, 0x58, 0xc1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xdb, 0xc0, 0x82, 0x30, 0x15, 0x79, 0x7f, 0xa6, 0x00, + 0x01, 0x18, 0x0b, 0xff, 0x08, 0x00, 0xff, 0xff, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x20, 0x01, 0xff, 0xff, 0x04, 0x46, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x81, 0x09, 0x15, 0xb3, 0x10, 0x1d, 0x00, + 0x24, 0x15, 0xb3, 0x00, 0x02, 0xeb, 0x8a, 0x95, 0x5c, +}; + +const uint8_t fby35_bb_fruid[] = { + 0x01, 0x00, 0x01, 0x03, 0x10, 0x00, 0x00, 0xeb, 0x01, 0x02, 0x17, 0xc3, + 0x4e, 0x2f, 0x41, 0xc3, 0x4e, 0x2f, 0x41, 0xc1, 0x00, 0x00, 0x00, 0x23, + 0x01, 0x0d, 0x00, 0xb6, 0xd2, 0xd0, 0xc6, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0xd5, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x77, 0x42, 0x4d, 0x43, 0xcd, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e, 0x30, 0xc9, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x0c, 0x00, 0xc6, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x59, 0x6f, 0x73, 0x65, 0x6d, + 0x69, 0x74, 0x65, 0x20, 0x56, 0x33, 0x2e, 0x35, 0x20, 0x45, 0x56, 0x54, + 0x32, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0xc4, 0x45, 0x56, 0x54, 0x32, 0xcd, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc7, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e, 0x30, 0xc9, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x4e, 0x2f, + 0x41, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, +}; + +const uint8_t fby35_bmc_fruid[] = { + 0x01, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, 0xf1, 0x01, 0x0c, 0x00, 0x36, + 0xe6, 0xd0, 0xc6, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x42, 0x4d, + 0x43, 0x20, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x4d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0xcd, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e, + 0x30, 0xc9, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc1, 0x39, 0x01, 0x0c, 0x00, 0xc6, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x59, 0x6f, 0x73, 0x65, 0x6d, + 0x69, 0x74, 0x65, 0x20, 0x56, 0x33, 0x2e, 0x35, 0x20, 0x45, 0x56, 0x54, + 0x32, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0xc4, 0x45, 0x56, 0x54, 0x32, 0xcd, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc7, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e, 0x30, 0xc9, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc8, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x20, 0x41, 0xc1, 0x45, +}; + +const size_t fby35_nic_fruid_len = sizeof(fby35_nic_fruid); +const size_t fby35_bb_fruid_len = sizeof(fby35_bb_fruid); +const size_t fby35_bmc_fruid_len = sizeof(fby35_bmc_fruid); diff --git a/hw/arm/aspeed_eeprom.h b/hw/arm/aspeed_eeprom.h new file mode 100644 index 0000000000..a0f848fa6e --- /dev/null +++ b/hw/arm/aspeed_eeprom.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef ASPEED_EEPROM_H +#define ASPEED_EEPROM_H + +#include "qemu/osdep.h" + +extern const uint8_t fby35_nic_fruid[]; +extern const uint8_t fby35_bb_fruid[]; +extern const uint8_t fby35_bmc_fruid[]; +extern const size_t fby35_nic_fruid_len; +extern const size_t fby35_bb_fruid_len; +extern const size_t fby35_bmc_fruid_len; + +#endif diff --git a/hw/arm/meson.build b/hw/arm/meson.build index b036045603..b545ba0e4f 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -51,6 +51,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed.c', 'aspeed_ast2600.c', 'aspeed_ast10x0.c', + 'aspeed_eeprom.c', 'fby35.c')) arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) From 4f2c6448c3b074ca45c0743b1e98df3a2c6e0fe2 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 614/814] hw/nvram/eeprom_at24c: Make reset behavior more like hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EEPROM's are a form of non-volatile memory. After power-cycling an EEPROM, I would expect the I2C state machine to be reset to default values, but I wouldn't really expect the memory to change at all. The current implementation of the at24c EEPROM resets its internal memory on reset. This matches the specification in docs/devel/reset.rst: Cold reset is supported by every resettable object. In QEMU, it means we reset to the initial state corresponding to the start of QEMU; this might differ from what is a real hardware cold reset. It differs from other resets (like warm or bus resets) which may keep certain parts untouched. But differs from my intuition. For example, if someone writes some information to an EEPROM, then AC power cycles their board, they would expect the EEPROM to retain that information. It's very useful to be able to test things like this in QEMU as well, to verify software instrumentation like determining the cause of a reboot. Fixes: 5d8424dbd3e8 ("nvram: add AT24Cx i2c eeprom") Signed-off-by: Peter Delevoryas Reviewed-by: Joel Stanley Reviewed-by: Cédric Le Goater Reviewed-by: Corey Minyard Link: https://lore.kernel.org/r/20230128060543.95582-6-peter@pjd.dev Signed-off-by: Cédric Le Goater --- hw/nvram/eeprom_at24c.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index 05598699dc..3328c32814 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -184,18 +184,6 @@ static void at24c_eeprom_realize(DeviceState *dev, Error **errp) } ee->mem = g_malloc0(ee->rsize); - -} - -static -void at24c_eeprom_reset(DeviceState *state) -{ - EEPROMState *ee = AT24C_EE(state); - - ee->changed = false; - ee->cur = 0; - ee->haveaddr = 0; - memset(ee->mem, 0, ee->rsize); if (ee->init_rom) { @@ -213,6 +201,16 @@ void at24c_eeprom_reset(DeviceState *state) } } +static +void at24c_eeprom_reset(DeviceState *state) +{ + EEPROMState *ee = AT24C_EE(state); + + ee->changed = false; + ee->cur = 0; + ee->haveaddr = 0; +} + static Property at24c_eeprom_props[] = { DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0), DEFINE_PROP_BOOL("writable", EEPROMState, writable, true), From 6fdb43818712e52891f790984d4e8a4bf8a166ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 615/814] hw/watchdog/wdt_aspeed: Rename MMIO region size as 'iosize' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid confusing two different things: - the WDT I/O region size ('iosize') - at which offset the SoC map the WDT ('offset') While it is often the same, we can map smaller region sizes at larger offsets. Here we are interested in the I/O region size, so rename as 'iosize'. Reviewed-by: Peter Delevoryas Signed-off-by: Philippe Mathieu-Daudé [ clg: Introduced temporary wdt_offset variable ] Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 4 ++-- hw/arm/aspeed_ast2600.c | 4 ++-- hw/arm/aspeed_soc.c | 4 ++-- hw/watchdog/wdt_aspeed.c | 8 ++++---- include/hw/watchdog/wdt_aspeed.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 4d0b9b115f..b483735dc2 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -318,14 +318,14 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); + hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize; object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, - sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* GPIO */ diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index cd75465c2b..bb2769df04 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -465,14 +465,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); + hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize; object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, - sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* RAM */ diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index b05b9dd416..e884d6badc 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -386,14 +386,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); + hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize; object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, - sc->memmap[ASPEED_DEV_WDT] + i * awc->offset); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* RAM */ diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index d753693a2e..958725a1b5 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -309,7 +309,7 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); dc->desc = "ASPEED 2400 Watchdog Controller"; - awc->offset = 0x20; + awc->iosize = 0x20; awc->ext_pulse_width_mask = 0xff; awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->wdt_reload = aspeed_wdt_reload; @@ -346,7 +346,7 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); dc->desc = "ASPEED 2500 Watchdog Controller"; - awc->offset = 0x20; + awc->iosize = 0x20; awc->ext_pulse_width_mask = 0xfffff; awc->reset_ctrl_reg = SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; @@ -369,7 +369,7 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); dc->desc = "ASPEED 2600 Watchdog Controller"; - awc->offset = 0x40; + awc->iosize = 0x40; awc->ext_pulse_width_mask = 0xfffff; /* TODO */ awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; @@ -392,7 +392,7 @@ static void aspeed_1030_wdt_class_init(ObjectClass *klass, void *data) AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); dc->desc = "ASPEED 1030 Watchdog Controller"; - awc->offset = 0x80; + awc->iosize = 0x80; awc->ext_pulse_width_mask = 0xfffff; /* TODO */ awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1; awc->reset_pulse = aspeed_2500_wdt_reset_pulse; diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index dfa5dfa424..db91ee6b51 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -40,7 +40,7 @@ struct AspeedWDTState { struct AspeedWDTClass { SysBusDeviceClass parent_class; - uint32_t offset; + uint32_t iosize; uint32_t ext_pulse_width_mask; uint32_t reset_ctrl_reg; void (*reset_pulse)(AspeedWDTState *s, uint32_t property); From 4ef247661e55da0ac7c29e8369ada2863f759b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 616/814] hw/watchdog/wdt_aspeed: Extend MMIO range to cover more registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When booting the Zephyr demo in [1] we get: aspeed.io: unimplemented device write (size 4, offset 0x185128, value 0x030f1ff1) <-- aspeed.io: unimplemented device write (size 4, offset 0x18512c, value 0x03fffff1) This corresponds to this Zephyr code [2]: static int aspeed_wdt_init(const struct device *dev) { const struct aspeed_wdt_config *config = dev->config; struct aspeed_wdt_data *const data = dev->data; uint32_t reg_val; /* disable WDT by default */ reg_val = sys_read32(config->ctrl_base + WDT_CTRL_REG); reg_val &= ~WDT_CTRL_ENABLE; sys_write32(reg_val, config->ctrl_base + WDT_CTRL_REG); sys_write32(data->rst_mask1, config->ctrl_base + WDT_SW_RESET_MASK1_REG); <------ sys_write32(data->rst_mask2, config->ctrl_base + WDT_SW_RESET_MASK2_REG); return 0; } The register definitions are [3]: #define WDT_RELOAD_VAL_REG 0x0004 #define WDT_RESTART_REG 0x0008 #define WDT_CTRL_REG 0x000C #define WDT_TIMEOUT_STATUS_REG 0x0010 #define WDT_TIMEOUT_STATUS_CLR_REG 0x0014 #define WDT_RESET_MASK1_REG 0x001C #define WDT_RESET_MASK2_REG 0x0020 #define WDT_SW_RESET_MASK1_REG 0x0028 <------ #define WDT_SW_RESET_MASK2_REG 0x002C #define WDT_SW_RESET_CTRL_REG 0x0024 Currently QEMU only cover a MMIO region of size 0x20: #define ASPEED_WDT_REGS_MAX (0x20 / 4) Change to map the whole 'iosize' which might be bigger, covering the other registers. The MemoryRegionOps read/write handlers will report the accesses as out-of-bounds guest-errors, but the next commit will report them as unimplemented. [1] https://github.com/AspeedTech-BMC/zephyr/releases/tag/v00.01.07 [2] https://github.com/AspeedTech-BMC/zephyr/commit/2e99f10ac27b [3] https://github.com/AspeedTech-BMC/zephyr/blob/v00.01.08/drivers/watchdog/wdt_aspeed.c#L31 Reviewed-by: Peter Delevoryas Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- hw/watchdog/wdt_aspeed.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 958725a1b5..eefca31ae4 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -260,6 +260,7 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedWDTState *s = ASPEED_WDT(dev); + AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(dev); assert(s->scu); @@ -271,7 +272,7 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) s->pclk_freq = PCLK_HZ; memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops, s, - TYPE_ASPEED_WDT, ASPEED_WDT_REGS_MAX * 4); + TYPE_ASPEED_WDT, awc->iosize); sysbus_init_mmio(sbd, &s->iomem); } From f8ad895824860b1c18f1fd64e566d66ce70a61cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 617/814] hw/watchdog/wdt_aspeed: Log unimplemented registers as UNIMP level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add more Aspeed watchdog registers from [*]. Since guests can righteously access them, log the access at 'unimplemented' level instead of 'guest-errors'. [*] https://github.com/AspeedTech-BMC/zephyr/blob/v00.01.08/drivers/watchdog/wdt_aspeed.c#L31 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas Signed-off-by: Cédric Le Goater --- hw/watchdog/wdt_aspeed.c | 13 +++++++++++++ include/hw/watchdog/wdt_aspeed.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index eefca31ae4..d267aa185c 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -42,6 +42,11 @@ #define WDT_PUSH_PULL_MAGIC (0xA8 << 24) #define WDT_OPEN_DRAIN_MAGIC (0x8A << 24) #define WDT_RESET_MASK1 (0x1c / 4) +#define WDT_RESET_MASK2 (0x20 / 4) + +#define WDT_SW_RESET_CTRL (0x24 / 4) +#define WDT_SW_RESET_MASK1 (0x28 / 4) +#define WDT_SW_RESET_MASK2 (0x2c / 4) #define WDT_TIMEOUT_STATUS (0x10 / 4) #define WDT_TIMEOUT_CLEAR (0x14 / 4) @@ -83,6 +88,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) return s->regs[WDT_RESET_MASK1]; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: + case WDT_RESET_MASK2: + case WDT_SW_RESET_CTRL: + case WDT_SW_RESET_MASK1: + case WDT_SW_RESET_MASK2: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -190,6 +199,10 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: + case WDT_RESET_MASK2: + case WDT_SW_RESET_CTRL: + case WDT_SW_RESET_MASK1: + case WDT_SW_RESET_MASK2: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index db91ee6b51..e90ef86651 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -21,7 +21,7 @@ OBJECT_DECLARE_TYPE(AspeedWDTState, AspeedWDTClass, ASPEED_WDT) #define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600" #define TYPE_ASPEED_1030_WDT TYPE_ASPEED_WDT "-ast1030" -#define ASPEED_WDT_REGS_MAX (0x20 / 4) +#define ASPEED_WDT_REGS_MAX (0x30 / 4) struct AspeedWDTState { /*< private >*/ From ed5d9774c624918977b2f274bb2e47c74047102d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 618/814] hw/misc/aspeed_hace: Do not crash if address_space_map() failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit address_space_map() can fail: uart:~$ hash test sha256_test tv[0]: Segmentation fault: 11 Thread 3 "qemu-system-arm" received signal SIGSEGV, Segmentation fault. gen_acc_mode_iov (req_len=0x7ffff18b7778, id=, iov=0x7ffff18b7780, s=0x555556ce0bd0) at ../hw/misc/aspeed_hace.c:171 171 if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) { (gdb) bt #0 gen_acc_mode_iov (req_len=0x7ffff18b7778, id=, iov=0x7ffff18b7780, s=0x555556ce0bd0) at ../hw/misc/aspeed_hace.c:171 #1 do_hash_operation (s=s@entry=0x555556ce0bd0, algo=3, sg_mode=sg_mode@entry=true, acc_mode=acc_mode@entry=true) at ../hw/misc/aspeed_hace.c:224 #2 0x00005555559bdbb8 in aspeed_hace_write (opaque=, addr=12, data=262488, size=) at ../hw/misc/aspeed_hace.c:358 This change doesn't fix much, but at least the guest can't crash QEMU anymore. Instead it is still usable: uart:~$ hash test sha256_test tv[0]:hash_final error sha384_test tv[0]:hash_final error sha512_test tv[0]:hash_final error [00:00:06.278,000] hace_global: HACE poll timeout [00:00:09.324,000] hace_global: HACE poll timeout [00:00:12.261,000] hace_global: HACE poll timeout uart:~$ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index ac21be306c..12a761f1f5 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -193,6 +193,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, size_t digest_len = 0; int niov = 0; int i; + void *haddr; if (sg_mode) { uint32_t len = 0; @@ -217,9 +218,13 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, addr &= SG_LIST_ADDR_MASK; plen = len & SG_LIST_LEN_MASK; - iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false, - MEMTXATTRS_UNSPECIFIED); - + haddr = address_space_map(&s->dram_as, 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; if (acc_mode) { niov = gen_acc_mode_iov(s, iov, i, &plen); @@ -230,10 +235,14 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } else { hwaddr len = s->regs[R_HASH_SRC_LEN]; + haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], + &len, 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; - iov[0].iov_base = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], - &len, false, - MEMTXATTRS_UNSPECIFIED); i = 1; if (s->iov_count) { From 72006c619f6ae62cd1e954f8ff8436447525e202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 619/814] hw/arm/aspeed_ast10x0: Add various unimplemented peripherals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on booting Zephyr demo from [1] running QEMU with '-d unimp' and checking missing devices in [2]. [1] https://github.com/AspeedTech-BMC/zephyr/releases/tag/v00.01.07 [2] https://github.com/AspeedTech-BMC/zephyr/blob/v00.01.08/dts/arm/aspeed/ast10x0.dtsi Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Reviewed-by: Joel Stanley Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 35 +++++++++++++++++++++++++++++++++++ include/hw/arm/aspeed_soc.h | 11 +++++++++++ 2 files changed, 46 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index b483735dc2..b970a5ea58 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -27,10 +27,15 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = { [ASPEED_DEV_FMC] = 0x7E620000, [ASPEED_DEV_SPI1] = 0x7E630000, [ASPEED_DEV_SPI2] = 0x7E640000, + [ASPEED_DEV_UDC] = 0x7E6A2000, [ASPEED_DEV_SCU] = 0x7E6E2000, + [ASPEED_DEV_JTAG0] = 0x7E6E4000, + [ASPEED_DEV_JTAG1] = 0x7E6E4100, [ASPEED_DEV_ADC] = 0x7E6E9000, + [ASPEED_DEV_ESPI] = 0x7E6EE000, [ASPEED_DEV_SBC] = 0x7E6F2000, [ASPEED_DEV_GPIO] = 0x7E780000, + [ASPEED_DEV_SGPIOM] = 0x7E780500, [ASPEED_DEV_TIMER1] = 0x7E782000, [ASPEED_DEV_UART1] = 0x7E783000, [ASPEED_DEV_UART2] = 0x7E78D000, @@ -78,12 +83,17 @@ static const int aspeed_soc_ast1030_irqmap[] = { [ASPEED_DEV_LPC] = 35, [ASPEED_DEV_PECI] = 38, [ASPEED_DEV_FMC] = 39, + [ASPEED_DEV_ESPI] = 42, [ASPEED_DEV_PWM] = 44, [ASPEED_DEV_ADC] = 46, [ASPEED_DEV_SPI1] = 65, [ASPEED_DEV_SPI2] = 66, [ASPEED_DEV_I2C] = 110, /* 110 ~ 123 */ [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ + [ASPEED_DEV_UDC] = 9, + [ASPEED_DEV_SGPIOM] = 51, + [ASPEED_DEV_JTAG0] = 27, + [ASPEED_DEV_JTAG1] = 53, }; static qemu_irq aspeed_soc_ast1030_get_irq(AspeedSoCState *s, int dev) @@ -154,6 +164,15 @@ static void aspeed_soc_ast1030_init(Object *obj) object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "sbc-unimplemented", &s->sbc_unimplemented, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "pwm", &s->pwm, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "espi", &s->espi, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "udc", &s->udc, TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "sgpiom", &s->sgpiom, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "jtag[0]", &s->jtag[0], + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "jtag[1]", &s->jtag[1], + TYPE_UNIMPLEMENTED_DEVICE); } static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) @@ -336,6 +355,22 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->pwm), "aspeed.pwm", + sc->memmap[ASPEED_DEV_PWM], 0x100); + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->espi), "aspeed.espi", + sc->memmap[ASPEED_DEV_ESPI], 0x800); + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->udc), "aspeed.udc", + sc->memmap[ASPEED_DEV_UDC], 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->sgpiom), "aspeed.sgpiom", + sc->memmap[ASPEED_DEV_SGPIOM], 0x100); + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->jtag[0]), "aspeed.jtag", + sc->memmap[ASPEED_DEV_JTAG0], 0x20); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->jtag[1]), "aspeed.jtag", + sc->memmap[ASPEED_DEV_JTAG1], 0x20); } static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 8389200b2d..9a5e3c0bac 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -44,6 +44,7 @@ #define ASPEED_CPUS_NUM 2 #define ASPEED_MACS_NUM 4 #define ASPEED_UARTS_NUM 13 +#define ASPEED_JTAG_NUM 2 struct AspeedSoCState { /*< private >*/ @@ -87,6 +88,11 @@ struct AspeedSoCState { UnimplementedDeviceState video; UnimplementedDeviceState emmc_boot_controller; UnimplementedDeviceState dpmcu; + UnimplementedDeviceState pwm; + UnimplementedDeviceState espi; + UnimplementedDeviceState udc; + UnimplementedDeviceState sgpiom; + UnimplementedDeviceState jtag[ASPEED_JTAG_NUM]; }; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -174,6 +180,11 @@ enum { ASPEED_DEV_DPMCU, ASPEED_DEV_DP, ASPEED_DEV_I3C, + ASPEED_DEV_ESPI, + ASPEED_DEV_UDC, + ASPEED_DEV_SGPIOM, + ASPEED_DEV_JTAG0, + ASPEED_DEV_JTAG1, }; qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); From 29c4f0601f8e419972fb3a2f82a1dc259ca8d8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 620/814] hw/arm/aspeed_ast10x0: Map I3C peripheral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since I don't have access to the datasheet, the relevant values were found in: https://github.com/AspeedTech-BMC/zephyr/blob/v00.01.08/dts/arm/aspeed/ast10x0.dtsi Reviewed-by: Peter Delevoryas Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index b970a5ea58..1a06269cb1 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -53,6 +53,7 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = { [ASPEED_DEV_WDT] = 0x7E785000, [ASPEED_DEV_LPC] = 0x7E789000, [ASPEED_DEV_PECI] = 0x7E78B000, + [ASPEED_DEV_I3C] = 0x7E7A0000, [ASPEED_DEV_I2C] = 0x7E7B0000, }; @@ -88,6 +89,7 @@ static const int aspeed_soc_ast1030_irqmap[] = { [ASPEED_DEV_ADC] = 46, [ASPEED_DEV_SPI1] = 65, [ASPEED_DEV_SPI2] = 66, + [ASPEED_DEV_I3C] = 102, /* 102 -> 105 */ [ASPEED_DEV_I2C] = 110, /* 110 ~ 123 */ [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ [ASPEED_DEV_UDC] = 9, @@ -129,6 +131,8 @@ static void aspeed_soc_ast1030_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname); object_initialize_child(obj, "i2c", &s->i2c, typename); + object_initialize_child(obj, "i3c", &s->i3c, TYPE_ASPEED_I3C); + snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname); object_initialize_child(obj, "timerctrl", &s->timerctrl, typename); @@ -239,6 +243,18 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq); } + /* I3C */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); + for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) { + qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->armv7m), + sc->irqmap[ASPEED_DEV_I3C] + i); + /* The AST1030 I3C controller has one IRQ per bus. */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i3c.devices[i]), 0, irq); + } + /* PECI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { return; From 6ba3dc2516c53933e9b5e72acd6f9302f04ccbab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 621/814] hw/arm/aspeed_ast10x0: Map the secure SRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some SRAM appears to be used by the Secure Boot unit and crypto accelerators. Name it 'secure sram'. Note, the SRAM base address was already present but unused (the 'SBC' index is used for the MMIO peripheral). Interestingly using CFLAGS=-Winitializer-overrides reports: ../hw/arm/aspeed_ast10x0.c:32:30: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides] [ASPEED_DEV_SBC] = 0x7E6F2000, ^~~~~~~~~~ ../hw/arm/aspeed_ast10x0.c:24:30: note: previous initialization is here [ASPEED_DEV_SBC] = 0x79000000, ^~~~~~~~~~ This fixes with Zephyr: uart:~$ rsa test rsa test vector[0]: [00:00:26.156,000] os: ***** BUS FAULT ***** [00:00:26.157,000] os: Precise data bus error [00:00:26.157,000] os: BFAR Address: 0x79000000 [00:00:26.158,000] os: r0/a1: 0x79000000 r1/a2: 0x00000000 r2/a3: 0x00001800 [00:00:26.158,000] os: r3/a4: 0x79001800 r12/ip: 0x00000800 r14/lr: 0x0001098d [00:00:26.158,000] os: xpsr: 0x81000000 [00:00:26.158,000] os: Faulting instruction address (r15/pc): 0x0001e1bc [00:00:26.158,000] os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 [00:00:26.158,000] os: Current thread: 0x38248 (shell_uart) [00:00:26.165,000] os: Halting system Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas [ clg: Fixed size of Secure Boot Controller Memory ] Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 11 ++++++++++- include/hw/arm/aspeed_soc.h | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 1a06269cb1..592a19d988 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -21,7 +21,7 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = { [ASPEED_DEV_SRAM] = 0x00000000, - [ASPEED_DEV_SBC] = 0x79000000, + [ASPEED_DEV_SECSRAM] = 0x79000000, [ASPEED_DEV_IOMEM] = 0x7E600000, [ASPEED_DEV_PWM] = 0x7E610000, [ASPEED_DEV_FMC] = 0x7E620000, @@ -221,6 +221,14 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SRAM], &s->sram); + memory_region_init_ram(&s->secsram, OBJECT(s), "sec.sram", + sc->secsram_size, &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SECSRAM], + &s->secsram); /* SCU */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { @@ -400,6 +408,7 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); sc->silicon_rev = AST1030_A1_SILICON_REV; sc->sram_size = 0xc0000; + sc->secsram_size = 0x40000; /* 256 * KiB */ sc->spis_num = 2; sc->ehcis_num = 0; sc->wdts_num = 4; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 9a5e3c0bac..bd1e03e78a 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -71,6 +71,7 @@ struct AspeedSoCState { AspeedSMCState spi[ASPEED_SPIS_NUM]; EHCISysBusState ehci[ASPEED_EHCIS_NUM]; AspeedSBCState sbc; + MemoryRegion secsram; UnimplementedDeviceState sbc_unimplemented; AspeedSDMCState sdmc; AspeedWDTState wdt[ASPEED_WDTS_NUM]; @@ -105,6 +106,7 @@ struct AspeedSoCClass { const char *cpu_type; uint32_t silicon_rev; uint64_t sram_size; + uint64_t secsram_size; int spis_num; int ehcis_num; int wdts_num; @@ -143,6 +145,7 @@ enum { ASPEED_DEV_SCU, ASPEED_DEV_ADC, ASPEED_DEV_SBC, + ASPEED_DEV_SECSRAM, ASPEED_DEV_EMMC_BC, ASPEED_DEV_VIDEO, ASPEED_DEV_SRAM, From 98fb9678da1560f7a625bfa900a1579772627687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 622/814] hw/arm/aspeed_ast10x0: Map HACE peripheral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since I don't have access to the datasheet, the relevant values were found in: https://github.com/AspeedTech-BMC/zephyr/blob/v00.01.08/dts/arm/aspeed/ast10x0.dtsi Before on Zephyr: uart:~$ hash test sha256_test tv[0]:hash_final error sha384_test tv[0]:hash_final error sha512_test tv[0]:hash_final error [00:00:06.278,000] hace_global: HACE poll timeout [00:00:09.324,000] hace_global: HACE poll timeout [00:00:12.261,000] hace_global: HACE poll timeout uart:~$ crypto aes256_cbc_vault aes256_cbc vault key 1 [00:00:06.699,000] hace_global: aspeed_crypto_session_setup [00:00:06.699,000] hace_global: data->cmd: 1c2098 [00:00:06.699,000] hace_global: crypto_data_src: 93340 [00:00:06.699,000] hace_global: crypto_data_dst: 93348 [00:00:06.699,000] hace_global: crypto_ctx_base: 93300 [00:00:06.699,000] hace_global: crypto_data_len: 80000040 [00:00:06.699,000] hace_global: crypto_cmd_reg: 11c2098 [00:00:09.743,000] hace_global: HACE_STS: 0 [00:00:09.743,000] hace_global: HACE poll timeout [00:00:09.743,000] crypto: CBC mode ENCRYPT - Failed [00:00:09.743,000] hace_global: aspeed_crypto_session_free uart:~$ After: uart:~$ hash test sha256_test tv[0]:PASS tv[1]:PASS tv[2]:PASS tv[3]:PASS tv[4]:PASS sha384_test tv[0]:PASS tv[1]:PASS tv[2]:PASS tv[3]:PASS tv[4]:PASS tv[5]:PASS sha512_test tv[0]:PASS tv[1]:PASS tv[2]:PASS tv[3]:PASS tv[4]:PASS tv[5]:PASS uart:~$ crypto aes256_cbc_vault aes256_cbc vault key 1 Was waiting for: 6b c1 be e2 2e 40 9f 96 e9 3d 7e 11 73 93 17 2a ae 2d 8a 57 1e 03 ac 9c 9e b7 6f ac 45 af 8e 51 30 c8 1c 46 a3 5c e4 11 e5 fb c1 19 1a 0a 52 ef f6 9f 24 45 df 4f 9b 17 ad 2b 41 7b e6 6c 37 10 But got: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [00:00:05.771,000] hace_global: aspeed_crypto_session_setup [00:00:05.772,000] hace_global: data->cmd: 1c2098 [00:00:05.772,000] hace_global: crypto_data_src: 93340 [00:00:05.772,000] hace_global: crypto_data_dst: 93348 [00:00:05.772,000] hace_global: crypto_ctx_base: 93300 [00:00:05.772,000] hace_global: crypto_data_len: 80000040 [00:00:05.772,000] hace_global: crypto_cmd_reg: 11c2098 [00:00:05.772,000] hace_global: HACE_STS: 1000 [00:00:05.772,000] crypto: Output length (encryption): 80 [00:00:05.772,000] hace_global: aspeed_crypto_session_free [00:00:05.772,000] hace_global: aspeed_crypto_session_setup [00:00:05.772,000] hace_global: data->cmd: 1c2018 [00:00:05.772,000] hace_global: crypto_data_src: 93340 [00:00:05.772,000] hace_global: crypto_data_dst: 93348 [00:00:05.772,000] hace_global: crypto_ctx_base: 93300 [00:00:05.772,000] hace_global: crypto_data_len: 80000040 [00:00:05.772,000] hace_global: crypto_cmd_reg: 11c2018 [00:00:05.772,000] hace_global: HACE_STS: 1000 [00:00:05.772,000] crypto: Output length (decryption): 64 [00:00:05.772,000] crypto: CBC mode DECRYPT - Mismatch between plaintext and decrypted cipher text [00:00:05.774,000] hace_global: aspeed_crypto_session_free uart:~$ Reviewed-by: Peter Delevoryas Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 592a19d988..5c794c2420 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -28,6 +28,7 @@ static const hwaddr aspeed_soc_ast1030_memmap[] = { [ASPEED_DEV_SPI1] = 0x7E630000, [ASPEED_DEV_SPI2] = 0x7E640000, [ASPEED_DEV_UDC] = 0x7E6A2000, + [ASPEED_DEV_HACE] = 0x7E6D0000, [ASPEED_DEV_SCU] = 0x7E6E2000, [ASPEED_DEV_JTAG0] = 0x7E6E4000, [ASPEED_DEV_JTAG1] = 0x7E6E4100, @@ -165,6 +166,9 @@ static void aspeed_soc_ast1030_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); object_initialize_child(obj, "gpio", &s->gpio, typename); + snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname); + object_initialize_child(obj, "hace", &s->hace, typename); + object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "sbc-unimplemented", &s->sbc_unimplemented, TYPE_UNIMPLEMENTED_DEVICE); @@ -358,6 +362,17 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) } aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + /* HACE */ + object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(&s->sram), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + sc->memmap[ASPEED_DEV_HACE]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); + /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); From f16c27a52d6e408328539db6772f2d7a138e5b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 623/814] hw/arm/aspeed_ast10x0: Add TODO comment to use Cortex-M4F MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This SoC uses a Cortex-M4F. QEMU only implements a M4, which is good enough. Add a TODO note in case the M4F is added. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast10x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 5c794c2420..649b3b13c1 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -420,7 +420,7 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) dc->realize = aspeed_soc_ast1030_realize; sc->name = "ast1030-a1"; - sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); + sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-m4"); /* TODO cortex-m4f */ sc->silicon_rev = AST1030_A1_SILICON_REV; sc->sram_size = 0xc0000; sc->secsram_size = 0x40000; /* 256 * KiB */ From 44055caaa5225ed891a76e419e305336c603d8fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 624/814] tests/avocado: Test Aspeed Zephyr SDK v00.01.08 on AST1030 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a very quick test that runs some commands in a Zephyr shell: $ tests/venv/bin/avocado --show=app,console run -t os:zephyr tests/avocado (2/2) tests/avocado/machine_aspeed.py:AST1030Machine.test_ast1030_zephyros_1_07: console: *** Booting Zephyr OS build v00.01.07 *** console: ast1030_evb demo console: SOC: AST1030-A1 console: uart:~$ kernel stacks console: 0x36910 wdt_background (real size 1024): unused 988 usage 36 / 1024 (3 %) console: 0x36ad8 shell_uart (real size 4096): unused 3084 usage 1012 / 4096 (24 %) console: 0x2edb8 ADC0 (real size 400): unused 260 usage 140 / 400 (35 %) console: 0x2f0f0 ADC1 (real size 400): unused 260 usage 140 / 400 (35 %) console: 0x3b098 sysworkq (real size 1024): unused 860 usage 164 / 1024 (16 %) console: 0x36cc0 usbdworkq (real size 1024): unused 860 usage 164 / 1024 (16 %) console: 0x36bd8 usbworkq (real size 1024): unused 860 usage 164 / 1024 (16 %) console: 0x36a10 logging (real size 768): unused 548 usage 220 / 768 (28 %) console: 0x36ef8 idle 00 (real size 320): unused 268 usage 52 / 320 (16 %) console: 0x47800 IRQ 00 (real size 2048): unused 1504 usage 544 / 2048 (26 %) console: uart:~$ otp info scu console: SCU BIT reg_protect Description console: ____________________________________________________________________ console: 0x500 0x0 0x0 Disable ARM CM4 CPU boot (TXD5) console: 0x500 0x1 0x0 /Reserved console: 0x500 0x2 0x0 \ " console: 0x500 0x3 0x0 Address offset of single chip ABR mode console: 0x500 0x4 0x0 /Reserved console: 0x500 0x5 0x0 | " console: 0x500 0x6 0x0 | " console: 0x500 0x7 0x0 | " console: 0x500 0x8 0x0 | " console: 0x500 0x9 0x0 | " console: 0x500 0xA 0x0 | " console: 0x500 0xB 0x0 | " console: 0x500 0xC 0x0 | " console: 0x500 0xD 0x0 | " console: 0x500 0xE 0x0 | " console: 0x500 0xF 0x0 | " console: 0x500 0x10 0x0 \ " console: 0x500 0x11 0x0 Disabl3 ARM JTAG debug console: 0x500 0x12 0x0 /Reserved console: 0x500 0x13 0x0 | " console: 0x500 0x14 0x0 | " console: 0x500 0x15 0x0 | " console: 0x500 0x16 0x0 | " console: 0x500 0x17 0x0 | " console: 0x500 0x18 0x0 | " console: 0x500 0x19 0x0 | " console: 0x500 0x1A 0x0 | " console: 0x500 0x1B 0x0 | " console: 0x500 0x1C 0x0 | " console: 0x500 0x1D 0x0 | " console: 0x500 0x1E 0x0 | " console: 0x500 0x1F 0x0 \ " console: 0x510 0x0 0x0 /Reserved console: 0x510 0x1 0x0 | " console: 0x510 0x2 0x0 | " console: 0x510 0x3 0x0 \ " console: 0x510 0x4 0x0 Disable debug interfaces console: 0x510 0x5 0x0 /Reserved console: 0x510 0x6 0x0 | " console: 0x510 0x7 0x0 \ " console: 0x510 0x8 0x0 Enable boot from Uart5 by Pin Strap console: 0x510 0x9 0x0 /Reserved console: 0x510 0xA 0x0 \ " console: 0x510 0xB 0x0 Enable boot SPI ABR console: 0x510 0xC 0x0 Boot SPI ABR Mode console: 0x510 0xD 0x0 /Boot SPI flash size console: 0x510 0xE 0x0 | " console: 0x510 0xF 0x0 \ " console: 0x510 0x10 0x0 /Reserved console: 0x510 0x11 0x0 | " console: 0x510 0x12 0x0 | " console: 0x510 0x13 0x0 | " console: 0x510 0x14 0x0 | " console: 0x510 0x15 0x0 \ " console: 0x510 0x16 0x0 Enable boot SPI auxiliary control pins console: 0x510 0x19 0x0 /Reserved console: 0x510 0x1A 0x0 | " console: 0x510 0x1B 0x0 | " console: 0x510 0x1C 0x0 | " console: 0x510 0x1D 0x0 | " console: 0x510 0x1E 0x0 | " console: 0x510 0x1F 0x0 \ " console: 0x510 0x1E 0x0 Enable dedicate GPIO strap pins console: 0x510 0x1F 0x0 Enable Secure Boot by Pin Strap console: uart:~$ hwinfo devid console: Length: 8 console: ID: 0x0000018000000180 console: uart:~$ crypto aes256_cbc_vault console: aes256_cbc vault key 1 console: Was waiting for: console: 6b c1 be e2 2e 40 9f 96 e9 3d 7e 11 73 93 17 2a console: ae 2d 8a 57 1e 03 ac 9c 9e b7 6f ac 45 af 8e 51 console: 30 c8 1c 46 a3 5c e4 11 e5 fb c1 19 1a 0a 52 ef console: f6 9f 24 45 df 4f 9b 17 ad 2b 41 7b e6 6c 37 10 console: But got: console: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 console: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 console: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 console: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 console: uart:~$ random get console: 0x862460d console: uart:~$ i2c scan I2C_0 console: 0 1 2 3 4 5 6 7 8 9 a b c d e f console: 00: -- -- -- -- -- -- -- -- -- -- -- -- console: 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- console: 70: -- -- -- -- -- -- -- -- console: 1 devices found on I2C_0 console: uart:~$ kernel uptime console: Uptime: 9897 ms console: uart:~$ kernel reboot warm console: *** Booting Zephyr OS build v00.01.07 *** PASS (1.08 s) Ref: https://github.com/AspeedTech-BMC/zephyr/releases/download/v00.01.07/Aspeed_Zephy_SDK_User_Guide_v00.01.07.pdf Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Delevoryas Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- tests/avocado/machine_aspeed.py | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py index 1cab946727..ddf05b3617 100644 --- a/tests/avocado/machine_aspeed.py +++ b/tests/avocado/machine_aspeed.py @@ -22,10 +22,11 @@ class AST1030Machine(QemuSystemTest): timeout = 10 - def test_ast1030_zephyros(self): + def test_ast1030_zephyros_1_04(self): """ :avocado: tags=arch:arm :avocado: tags=machine:ast1030-evb + :avocado: tags=os:zephyr """ tar_url = ('https://github.com/AspeedTech-BMC' '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip') @@ -41,6 +42,44 @@ class AST1030Machine(QemuSystemTest): exec_command_and_wait_for_pattern(self, "help", "Available commands") + def test_ast1030_zephyros_1_07(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:ast1030-evb + :avocado: tags=os:zephyr + """ + tar_url = ('https://github.com/AspeedTech-BMC' + '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip') + tar_hash = '40ac87eabdcd3b3454ce5aad11fedc72a33ecda2' + tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash) + archive.extract(tar_path, self.workdir) + kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.bin" + self.vm.set_console() + self.vm.add_args('-kernel', kernel_file, + '-nographic') + self.vm.launch() + wait_for_console_pattern(self, "Booting Zephyr OS") + for shell_cmd in [ + 'kernel stacks', + 'otp info conf', + 'otp info scu', + 'hwinfo devid', + 'crypto aes256_cbc_vault', + 'random get', + 'jtag JTAG1 sw_xfer high TMS', + 'adc ADC0 resolution 12', + 'adc ADC0 read 42', + 'adc ADC1 read 69', + 'i2c scan I2C_0', + 'i3c attach I3C_0', + 'hash test', + 'kernel uptime', + 'kernel reboot warm', + 'kernel uptime', + 'kernel reboot cold', + 'kernel uptime', + ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$") + class AST2x00Machine(QemuSystemTest): timeout = 90 From bf81b8f8acda4f1f774adc5f8e76225d472c6ae5 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 7 Feb 2023 09:02:05 +0100 Subject: [PATCH 625/814] aspeed/sdmc: Drop unnecessary scu include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The model includes aspeed_scu.h but doesn't appear to require it. Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230124062022.298230-1-joel@jms.id.au> Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_sdmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index d2a3931033..abb2727933 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -12,7 +12,6 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "hw/misc/aspeed_sdmc.h" -#include "hw/misc/aspeed_scu.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qapi/error.h" From aa735872a879075d1e9d669c8d5737f41232a3e3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:11 +0100 Subject: [PATCH 626/814] scripts/clean-includes: Fully skip / ignore files When clean-includes claims to skip or ignore a file, only the part that sanitizes use of qemu/osdep.h skips the file. The part that looks for duplicate #include does not, and neither does committing to Git. The latter can get unrelated stuff included in the commit, but only if you run clean-includes in a dirty tree, which is unwise. Messed up when we added skipping in commit fd3e39a40c "scripts/clean-includes: Enhance to handle header files". The former can cause bogus reports for --check-dup-head. Added in commit d66253e46a "scripts/clean-includes: added duplicate #include check", duplicating the prior mistake. Fix the script to fully skip files. Fixes: fd3e39a40ca2 ("scripts/clean-includes: Enhance to handle header files") Fixes: d66253e46ae2 ("scripts/clean-includes: added duplicate #include check") Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Blake Message-Id: <20230202133830.2152150-2-armbru@redhat.com> --- scripts/clean-includes | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/clean-includes b/scripts/clean-includes index d37bd4f692..86944f27fc 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -111,6 +111,7 @@ cat >"$COCCIFILE" < 1) print $0}' if [ $? -eq 0 ]; then echo "Found duplicate header file includes. Please check the above files manually." @@ -184,7 +186,7 @@ if [ "$DUPHEAD" = "yes" ]; then fi if [ "$GIT" = "yes" ]; then - git add -- "$@" + git add -- $files git commit --signoff -F - < Date: Thu, 2 Feb 2023 14:38:12 +0100 Subject: [PATCH 627/814] scripts/clean-includes: Don't claim duplicate headers found when not When running with --check-dup-head, the script always claims it "Found duplicate header file includes." Fix to do it only when it actually found some. Fixes: d66253e46ae2 ("scripts/clean-includes: added duplicate #include check") Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Blake Message-Id: <20230202133830.2152150-3-armbru@redhat.com> --- scripts/clean-includes | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/clean-includes b/scripts/clean-includes index 86944f27fc..8e8420d785 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -177,9 +177,8 @@ for f in "$@"; do done if [ "$DUPHEAD" = "yes" ] && [ -n "$files" ]; then - egrep "^[[:space:]]*#[[:space:]]*include" $files | tr -d '[:blank:]' \ - | sort | uniq -c | awk '{if ($1 > 1) print $0}' - if [ $? -eq 0 ]; then + if egrep "^[[:space:]]*#[[:space:]]*include" $files | tr -d '[:blank:]' \ + | sort | uniq -c | grep -v '^ *1 '; then echo "Found duplicate header file includes. Please check the above files manually." exit 1 fi From 6a7f0515fd8f12377622dbbda1e794f28511192d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:13 +0100 Subject: [PATCH 628/814] scripts/clean-includes: Skip symbolic links When a symbolic link points to a file that needs cleaning, the script replaces the link with a cleaned regular file. Not wanted; skip them. We have a few symbolic links under subprojects/libvduse/ and subprojects/libvhost-user/. Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Blake Message-Id: <20230202133830.2152150-4-armbru@redhat.com> --- scripts/clean-includes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/clean-includes b/scripts/clean-includes index 8e8420d785..f0466a6262 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -113,6 +113,10 @@ EOT files= for f in "$@"; do + if [ -L "$f" ]; then + echo "SKIPPING $f (symbolic link)" + continue + fi case "$f" in *.c.inc) # These aren't standalone C source files From d598d9746e87cea8e92acd0d4f4320fe5d854440 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:14 +0100 Subject: [PATCH 629/814] scripts/clean-includes: Improve --git commit message The script drops #include "qemu/osdep.h" from headers. Mention it in the commit message it uses for --git. Signed-off-by: Markus Armbruster Reviewed-by: Juan Quintela Message-Id: <20230202133830.2152150-5-armbru@redhat.com> --- scripts/clean-includes | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/clean-includes b/scripts/clean-includes index f0466a6262..58e1607a82 100755 --- a/scripts/clean-includes +++ b/scripts/clean-includes @@ -193,11 +193,17 @@ if [ "$GIT" = "yes" ]; then git commit --signoff -F - < Date: Thu, 2 Feb 2023 14:38:15 +0100 Subject: [PATCH 630/814] bsd-user: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Warner Losh Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-6-armbru@redhat.com> --- bsd-user/arm/signal.c | 1 + bsd-user/arm/target_arch_cpu.c | 2 ++ bsd-user/bsd-proc.h | 4 ---- bsd-user/freebsd/os-sys.c | 1 + bsd-user/i386/signal.c | 1 + bsd-user/i386/target_arch_cpu.c | 3 +-- bsd-user/main.c | 4 +--- bsd-user/qemu.h | 1 - bsd-user/strace.c | 1 - bsd-user/x86_64/signal.c | 1 + bsd-user/x86_64/target_arch_cpu.c | 3 +-- 11 files changed, 9 insertions(+), 13 deletions(-) diff --git a/bsd-user/arm/signal.c b/bsd-user/arm/signal.c index 2b1dd745d1..9734407543 100644 --- a/bsd-user/arm/signal.c +++ b/bsd-user/arm/signal.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "qemu.h" /* diff --git a/bsd-user/arm/target_arch_cpu.c b/bsd-user/arm/target_arch_cpu.c index 02bf9149d5..fe38ae2210 100644 --- a/bsd-user/arm/target_arch_cpu.c +++ b/bsd-user/arm/target_arch_cpu.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ + +#include "qemu/osdep.h" #include "target_arch.h" void target_cpu_set_tls(CPUARMState *env, target_ulong newtls) diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h index 68b66e571d..a1061bffb8 100644 --- a/bsd-user/bsd-proc.h +++ b/bsd-user/bsd-proc.h @@ -20,11 +20,7 @@ #ifndef BSD_PROC_H_ #define BSD_PROC_H_ -#include -#include -#include #include -#include /* exit(2) */ static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1) diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c index 309e27b9d6..1676ec10f8 100644 --- a/bsd-user/freebsd/os-sys.c +++ b/bsd-user/freebsd/os-sys.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "qemu.h" #include "target_arch_sysarch.h" diff --git a/bsd-user/i386/signal.c b/bsd-user/i386/signal.c index 5dd975ce56..a3131047b8 100644 --- a/bsd-user/i386/signal.c +++ b/bsd-user/i386/signal.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "qemu.h" /* diff --git a/bsd-user/i386/target_arch_cpu.c b/bsd-user/i386/target_arch_cpu.c index d349e45299..2a3af2ddef 100644 --- a/bsd-user/i386/target_arch_cpu.c +++ b/bsd-user/i386/target_arch_cpu.c @@ -17,9 +17,8 @@ * along with this program; if not, see . */ -#include - #include "qemu/osdep.h" + #include "cpu.h" #include "qemu.h" #include "qemu/timer.h" diff --git a/bsd-user/main.c b/bsd-user/main.c index 6f09180d65..41290e16f9 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -18,12 +18,10 @@ * along with this program; if not, see . */ -#include -#include +#include "qemu/osdep.h" #include #include -#include "qemu/osdep.h" #include "qemu/help-texts.h" #include "qemu/units.h" #include "qemu/accel.h" diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index be6105385e..0ceecfb6df 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -17,7 +17,6 @@ #ifndef QEMU_H #define QEMU_H -#include "qemu/osdep.h" #include "cpu.h" #include "qemu/units.h" #include "exec/cpu_ldst.h" diff --git a/bsd-user/strace.c b/bsd-user/strace.c index a77d10dd6b..96499751eb 100644 --- a/bsd-user/strace.c +++ b/bsd-user/strace.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "qemu.h" diff --git a/bsd-user/x86_64/signal.c b/bsd-user/x86_64/signal.c index c3875bc4c6..46cb865180 100644 --- a/bsd-user/x86_64/signal.c +++ b/bsd-user/x86_64/signal.c @@ -16,6 +16,7 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "qemu.h" /* diff --git a/bsd-user/x86_64/target_arch_cpu.c b/bsd-user/x86_64/target_arch_cpu.c index be7bd10720..1d32f18907 100644 --- a/bsd-user/x86_64/target_arch_cpu.c +++ b/bsd-user/x86_64/target_arch_cpu.c @@ -17,9 +17,8 @@ * along with this program; if not, see . */ -#include - #include "qemu/osdep.h" + #include "cpu.h" #include "qemu.h" #include "qemu/timer.h" From f4124f831d29982f95cb53dd77b85be4643b4ced Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:16 +0100 Subject: [PATCH 631/814] crypto: Clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-7-armbru@redhat.com> --- crypto/block-luks-priv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/block-luks-priv.h b/crypto/block-luks-priv.h index dc2dd14e52..8fc967afcb 100644 --- a/crypto/block-luks-priv.h +++ b/crypto/block-luks-priv.h @@ -18,7 +18,6 @@ * */ -#include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/bswap.h" From d90b1e42362950ad31a4b143416d78a33a894294 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:17 +0100 Subject: [PATCH 632/814] hw/cxl: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-8-armbru@redhat.com> Acked-by: Jonathan Cameron --- include/hw/cxl/cxl_component.h | 2 -- include/hw/cxl/cxl_host.h | 1 - include/hw/cxl/cxl_pci.h | 1 - 3 files changed, 4 deletions(-) diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index 5dca21e95b..692d7a5507 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -15,9 +15,7 @@ #define CXL2_COMPONENT_CM_REGION_SIZE 0x1000 #define CXL2_COMPONENT_BLOCK_SIZE 0x10000 -#include "qemu/compiler.h" #include "qemu/range.h" -#include "qemu/typedefs.h" #include "hw/cxl/cxl_cdat.h" #include "hw/register.h" #include "qapi/error.h" diff --git a/include/hw/cxl/cxl_host.h b/include/hw/cxl/cxl_host.h index a1b662ce40..c9bc9c7c50 100644 --- a/include/hw/cxl/cxl_host.h +++ b/include/hw/cxl/cxl_host.h @@ -7,7 +7,6 @@ * COPYING file in the top-level directory. */ -#include "qemu/osdep.h" #include "hw/cxl/cxl.h" #include "hw/boards.h" diff --git a/include/hw/cxl/cxl_pci.h b/include/hw/cxl/cxl_pci.h index 01e15ed5b4..407be95b9e 100644 --- a/include/hw/cxl/cxl_pci.h +++ b/include/hw/cxl/cxl_pci.h @@ -10,7 +10,6 @@ #ifndef CXL_PCI_H #define CXL_PCI_H -#include "qemu/compiler.h" #define CXL_VENDOR_ID 0x1e98 From 626fb3c6a884583a425672f34c3837ed99365b27 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:18 +0100 Subject: [PATCH 633/814] hw/input: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-9-armbru@redhat.com> --- hw/input/tsc210x.c | 1 - include/hw/input/pl050.h | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index fdd5ff87d9..7eae5989f7 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -20,7 +20,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "hw/hw.h" #include "audio/audio.h" #include "qemu/timer.h" diff --git a/include/hw/input/pl050.h b/include/hw/input/pl050.h index 89ec4fafc9..4cb8985f31 100644 --- a/include/hw/input/pl050.h +++ b/include/hw/input/pl050.h @@ -10,7 +10,6 @@ #ifndef HW_PL050_H #define HW_PL050_H -#include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/input/ps2.h" From e09458005068c38f235e53cc4b079c200470b88b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:19 +0100 Subject: [PATCH 634/814] hw/tricore: Clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-10-armbru@redhat.com> --- include/hw/tricore/triboard.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/hw/tricore/triboard.h b/include/hw/tricore/triboard.h index 094c8bd563..4fdd2d7d97 100644 --- a/include/hw/tricore/triboard.h +++ b/include/hw/tricore/triboard.h @@ -18,7 +18,6 @@ * License along with this library; if not, see . */ -#include "qemu/osdep.h" #include "qapi/error.h" #include "hw/boards.h" #include "sysemu/sysemu.h" From c12a9848148bb3babf9a29bd965d82f79ecfba27 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:20 +0100 Subject: [PATCH 635/814] qga: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Konstantin Kostiuk Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-11-armbru@redhat.com> --- qga/commands-posix.c | 1 - qga/cutils.c | 3 ++- qga/cutils.h | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index ebd33a643c..079689d79a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -51,7 +51,6 @@ #else #include #endif -#include #ifdef CONFIG_SOLARIS #include #endif diff --git a/qga/cutils.c b/qga/cutils.c index b8e142ef64..b21bcf3683 100644 --- a/qga/cutils.c +++ b/qga/cutils.c @@ -2,8 +2,9 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ -#include "cutils.h" +#include "qemu/osdep.h" +#include "cutils.h" #include "qapi/error.h" /** diff --git a/qga/cutils.h b/qga/cutils.h index f0f30a7d28..c1f2f4b17a 100644 --- a/qga/cutils.h +++ b/qga/cutils.h @@ -1,8 +1,6 @@ #ifndef CUTILS_H_ #define CUTILS_H_ -#include "qemu/osdep.h" - int qga_open_cloexec(const char *name, int flags, mode_t mode); #endif /* CUTILS_H_ */ From c0e38aa8f58d0cf39c9feec3e3f75615b768d520 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:21 +0100 Subject: [PATCH 636/814] migration: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela Message-Id: <20230202133830.2152150-12-armbru@redhat.com> [Straightforward conflict with commit d5890ea0722 resolved] --- include/qemu/userfaultfd.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/qemu/userfaultfd.h b/include/qemu/userfaultfd.h index d764496f0b..18a4314212 100644 --- a/include/qemu/userfaultfd.h +++ b/include/qemu/userfaultfd.h @@ -15,7 +15,6 @@ #ifdef CONFIG_LINUX -#include "qemu/osdep.h" #include "exec/hwaddr.h" #include From e02e085c8b88b4f78ab56dbd57da8b7952b73d54 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:22 +0100 Subject: [PATCH 637/814] net: Clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-13-armbru@redhat.com> --- net/vmnet_int.h | 1 - 1 file changed, 1 deletion(-) diff --git a/net/vmnet_int.h b/net/vmnet_int.h index adf6e8c20d..d0b90594f2 100644 --- a/net/vmnet_int.h +++ b/net/vmnet_int.h @@ -10,7 +10,6 @@ #ifndef VMNET_INT_H #define VMNET_INT_H -#include "qemu/osdep.h" #include "vmnet_int.h" #include "clients.h" From 1beb07ca8a95e202d525fbdceb2a9209d253b971 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:23 +0100 Subject: [PATCH 638/814] target/hexagon: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Changes to standalone programs dropped, because these intentionally don't use qemu/osdep.h: target/hexagon/gen_dectree_import.c target/hexagon/gen_semantics.c target/hexagon/idef-parser/idef-parser.h target/hexagon/idef-parser/parser-helpers.c target/hexagon/idef-parser/parser-helpers.h Signed-off-by: Markus Armbruster Reviewed-by: Taylor Simpson Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-14-armbru@redhat.com> --- target/hexagon/hex_arch_types.h | 1 - target/hexagon/mmvec/macros.h | 1 - 2 files changed, 2 deletions(-) diff --git a/target/hexagon/hex_arch_types.h b/target/hexagon/hex_arch_types.h index 885f68f760..52a7f2b2f3 100644 --- a/target/hexagon/hex_arch_types.h +++ b/target/hexagon/hex_arch_types.h @@ -18,7 +18,6 @@ #ifndef HEXAGON_HEX_ARCH_TYPES_H #define HEXAGON_HEX_ARCH_TYPES_H -#include "qemu/osdep.h" #include "mmvec/mmvec.h" #include "qemu/int128.h" diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index 8c864e8c68..1201d778d0 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -18,7 +18,6 @@ #ifndef HEXAGON_MMVEC_MACROS_H #define HEXAGON_MMVEC_MACROS_H -#include "qemu/osdep.h" #include "qemu/host-utils.h" #include "arch.h" #include "mmvec/system_ext_mmvec.h" From 06e2b0107fedf9ebef2d175a06a66c82015af11b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:24 +0100 Subject: [PATCH 639/814] riscv: Clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-15-armbru@redhat.com> --- target/riscv/pmu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h index 3004ce37b6..0c819ca983 100644 --- a/target/riscv/pmu.h +++ b/target/riscv/pmu.h @@ -16,7 +16,6 @@ * this program. If not, see . */ -#include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" #include "qemu/main-loop.h" From 02f95e91a66bf4027317591090350e3fb7e700de Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:25 +0100 Subject: [PATCH 640/814] block: Clean up includes This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Michael S. Tsirkin Reviewed-by: Eric Blake Message-Id: <20230202133830.2152150-16-armbru@redhat.com> --- block/qapi.c | 1 - include/block/graph-lock.h | 1 - include/block/write-threshold.h | 2 -- 3 files changed, 4 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index d52f1ab614..c84147849d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -40,7 +40,6 @@ #include "qapi/qmp/qstring.h" #include "qemu/qemu-print.h" #include "sysemu/block-backend.h" -#include "qemu/cutils.h" BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs, diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h index 3ab924d5e2..18cc14de22 100644 --- a/include/block/graph-lock.h +++ b/include/block/graph-lock.h @@ -20,7 +20,6 @@ #ifndef GRAPH_LOCK_H #define GRAPH_LOCK_H -#include "qemu/osdep.h" #include "qemu/clang-tsa.h" /** diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index f50f923e7e..63d1583887 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -13,8 +13,6 @@ #ifndef BLOCK_WRITE_THRESHOLD_H #define BLOCK_WRITE_THRESHOLD_H -#include "qemu/typedefs.h" - /* * bdrv_write_threshold_set: * From d35d5047a68e45020102aa4ad8e4be8ce6934600 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:26 +0100 Subject: [PATCH 641/814] accel: Clean up includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. All .c should include qemu/osdep.h first. The script performs three related cleanups: * Ensure .c files include qemu/osdep.h first. * Including it in a .h is redundant, since the .c already includes it. Drop such inclusions. * Likewise, including headers qemu/osdep.h includes is redundant. Drop these, too. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-17-armbru@redhat.com> --- include/sysemu/accel-blocker.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sysemu/accel-blocker.h b/include/sysemu/accel-blocker.h index 72020529ef..0733783bcc 100644 --- a/include/sysemu/accel-blocker.h +++ b/include/sysemu/accel-blocker.h @@ -14,7 +14,6 @@ #ifndef ACCEL_BLOCKER_H #define ACCEL_BLOCKER_H -#include "qemu/osdep.h" #include "sysemu/cpus.h" extern void accel_blocker_init(void); From 2ca10faeb85e3c1b87e10bb46786445a5a879bbd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:27 +0100 Subject: [PATCH 642/814] Fix non-first inclusions of qemu/osdep.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit was created with scripts/clean-includes. Signed-off-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela Message-Id: <20230202133830.2152150-18-armbru@redhat.com> --- audio/sndioaudio.c | 2 +- backends/hostmem-epc.c | 2 +- block/export/vduse-blk.c | 2 +- hw/hyperv/syndbg.c | 2 +- util/async-teardown.c | 12 ++++-------- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/audio/sndioaudio.c b/audio/sndioaudio.c index 632b0e3825..3fde01fdbd 100644 --- a/audio/sndioaudio.c +++ b/audio/sndioaudio.c @@ -14,9 +14,9 @@ * to recording, which is what guest systems expect. */ +#include "qemu/osdep.h" #include #include -#include "qemu/osdep.h" #include "qemu/main-loop.h" #include "audio.h" #include "trace.h" diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c index 037292d267..4e162d6789 100644 --- a/backends/hostmem-epc.c +++ b/backends/hostmem-epc.c @@ -9,9 +9,9 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ -#include #include "qemu/osdep.h" +#include #include "qom/object_interfaces.h" #include "qapi/error.h" #include "sysemu/hostmem.h" diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c index 350d6fdaf0..f7ae44e3ce 100644 --- a/block/export/vduse-blk.c +++ b/block/export/vduse-blk.c @@ -10,9 +10,9 @@ * later. See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include -#include "qemu/osdep.h" #include "qapi/error.h" #include "block/export.h" #include "qemu/error-report.h" diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c index 16d04cfdc6..94fe1b534b 100644 --- a/hw/hyperv/syndbg.c +++ b/hw/hyperv/syndbg.c @@ -5,8 +5,8 @@ * See the COPYING file in the top-level directory. */ -#include "qemu/ctype.h" #include "qemu/osdep.h" +#include "qemu/ctype.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/sockets.h" diff --git a/util/async-teardown.c b/util/async-teardown.c index 62bfce1b3c..62cdeb0f20 100644 --- a/util/async-teardown.c +++ b/util/async-teardown.c @@ -10,16 +10,12 @@ * option) any later version. See the COPYING file in the top-level directory. * */ -#include -#include -#include -#include -#include -#include -#include -#include #include "qemu/osdep.h" +#include +#include +#include + #include "qemu/async-teardown.h" #ifdef _SC_THREAD_STACK_MIN From bfe7bf8590a74aebd572abe56927b53f4978ab42 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:28 +0100 Subject: [PATCH 643/814] Don't include headers already included by qemu/osdep.h This commit was created with scripts/clean-includes. Signed-off-by: Markus Armbruster Acked-by: Christian Schoenebeck Reviewed-by: Michael S. Tsirkin Message-Id: <20230202133830.2152150-19-armbru@redhat.com> --- accel/tcg/cpu-exec.c | 1 - backends/tpm/tpm_ioctl.h | 2 -- fsdev/p9array.h | 2 -- hw/9pfs/9p.c | 2 -- hw/display/virtio-gpu-udmabuf.c | 1 - hw/i2c/pmbus_device.c | 1 - hw/remote/proxy-memory-listener.c | 1 - hw/sensor/adm1272.c | 1 - hw/usb/dev-storage-bot.c | 1 - hw/usb/dev-storage-classic.c | 1 - include/hw/misc/aspeed_lpc.h | 2 -- include/hw/pci/pcie_doe.h | 1 - include/qemu/async-teardown.h | 2 -- include/qemu/dbus.h | 1 - include/qemu/host-utils.h | 1 - include/sysemu/event-loop-base.h | 1 - softmmu/vl.c | 2 -- tcg/tci.c | 1 - tests/unit/test-seccomp.c | 1 - ui/udmabuf.c | 1 - util/main-loop.c | 1 - util/oslib-posix.c | 2 -- 22 files changed, 29 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 9c857eeb07..5357608b14 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -28,7 +28,6 @@ #include "exec/exec-all.h" #include "tcg/tcg.h" #include "qemu/atomic.h" -#include "qemu/compiler.h" #include "qemu/timer.h" #include "qemu/rcu.h" #include "exec/log.h" diff --git a/backends/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h index e506ef5160..b1d31768a6 100644 --- a/backends/tpm/tpm_ioctl.h +++ b/backends/tpm/tpm_ioctl.h @@ -12,8 +12,6 @@ # define __USE_LINUX_IOCTL_DEFS #endif -#include -#include #ifndef _WIN32 #include #include diff --git a/fsdev/p9array.h b/fsdev/p9array.h index 90e83a7c7b..50a1b15fe9 100644 --- a/fsdev/p9array.h +++ b/fsdev/p9array.h @@ -27,8 +27,6 @@ #ifndef QEMU_P9ARRAY_H #define QEMU_P9ARRAY_H -#include "qemu/compiler.h" - /** * P9Array provides a mechanism to access arrays in common C-style (e.g. by * square bracket [] operator) in conjunction with reference variables that diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 072cf67956..9621ec1341 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -19,8 +19,6 @@ #include "qemu/osdep.h" #ifdef CONFIG_LINUX #include -#else -#include #endif #include #include "hw/virtio/virtio.h" diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 8bdf4bac6e..847fa4c0cc 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -21,7 +21,6 @@ #include "exec/ramblock.h" #include "sysemu/hostmem.h" #include -#include #include #include "qemu/memfd.h" #include "standard-headers/linux/udmabuf.h" diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c index 4071a88cfc..c3d6046784 100644 --- a/hw/i2c/pmbus_device.c +++ b/hw/i2c/pmbus_device.c @@ -8,7 +8,6 @@ #include "qemu/osdep.h" #include -#include #include "hw/i2c/pmbus_device.h" #include "migration/vmstate.h" #include "qemu/module.h" diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index eb9918fe72..18d96a1d04 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -8,7 +8,6 @@ #include "qemu/osdep.h" -#include "qemu/compiler.h" #include "qemu/int128.h" #include "qemu/range.h" #include "exec/memory.h" diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c index 7310c769be..8f4a1c2cd4 100644 --- a/hw/sensor/adm1272.c +++ b/hw/sensor/adm1272.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include #include "hw/i2c/pmbus_device.h" #include "hw/irq.h" #include "migration/vmstate.h" diff --git a/hw/usb/dev-storage-bot.c b/hw/usb/dev-storage-bot.c index b24b3148c2..1e5c5c711f 100644 --- a/hw/usb/dev-storage-bot.c +++ b/hw/usb/dev-storage-bot.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu/typedefs.h" #include "qapi/error.h" #include "hw/usb.h" #include "hw/usb/desc.h" diff --git a/hw/usb/dev-storage-classic.c b/hw/usb/dev-storage-classic.c index 00f25bade2..84d19752b5 100644 --- a/hw/usb/dev-storage-classic.c +++ b/hw/usb/dev-storage-classic.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu/typedefs.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/usb.h" diff --git a/include/hw/misc/aspeed_lpc.h b/include/hw/misc/aspeed_lpc.h index fd228731d2..fa398959af 100644 --- a/include/hw/misc/aspeed_lpc.h +++ b/include/hw/misc/aspeed_lpc.h @@ -12,8 +12,6 @@ #include "hw/sysbus.h" -#include - #define TYPE_ASPEED_LPC "aspeed.lpc" #define ASPEED_LPC(obj) OBJECT_CHECK(AspeedLPCState, (obj), TYPE_ASPEED_LPC) diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h index ba4d8b03bd..87dc17dcef 100644 --- a/include/hw/pci/pcie_doe.h +++ b/include/hw/pci/pcie_doe.h @@ -11,7 +11,6 @@ #define PCIE_DOE_H #include "qemu/range.h" -#include "qemu/typedefs.h" #include "hw/register.h" /* diff --git a/include/qemu/async-teardown.h b/include/qemu/async-teardown.h index 092e7a37e7..b281da005b 100644 --- a/include/qemu/async-teardown.h +++ b/include/qemu/async-teardown.h @@ -13,8 +13,6 @@ #ifndef QEMU_ASYNC_TEARDOWN_H #define QEMU_ASYNC_TEARDOWN_H -#include "config-host.h" - #ifdef CONFIG_LINUX void init_async_teardown(void); #endif diff --git a/include/qemu/dbus.h b/include/qemu/dbus.h index 08f00dfd53..81d3de8a5a 100644 --- a/include/qemu/dbus.h +++ b/include/qemu/dbus.h @@ -15,7 +15,6 @@ #include "qom/object.h" #include "chardev/char.h" #include "qemu/notify.h" -#include "qemu/typedefs.h" /* glib/gio 2.68 */ #define DBUS_METHOD_INVOCATION_HANDLED TRUE diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 88d476161c..3ce62bf4a5 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -30,7 +30,6 @@ #ifndef HOST_UTILS_H #define HOST_UTILS_H -#include "qemu/compiler.h" #include "qemu/bswap.h" #include "qemu/int128.h" diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h index 2748bf6ae1..a6c24f1351 100644 --- a/include/sysemu/event-loop-base.h +++ b/include/sysemu/event-loop-base.h @@ -14,7 +14,6 @@ #include "qom/object.h" #include "block/aio.h" -#include "qemu/typedefs.h" #define TYPE_EVENT_LOOP_BASE "event-loop-base" OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass, diff --git a/softmmu/vl.c b/softmmu/vl.c index 9177d95d4e..5355a7fe5a 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -136,8 +136,6 @@ #include "qemu/guest-random.h" #include "qemu/keyval.h" -#include "config-host.h" - #define MAX_VIRTIO_CONSOLES 1 typedef struct BlockdevOptionsQueueEntry { diff --git a/tcg/tci.c b/tcg/tci.c index 022fe9d0f8..fc67e7e767 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -21,7 +21,6 @@ #include "exec/cpu_ldst.h" #include "tcg/tcg-op.h" #include "tcg/tcg-ldst.h" -#include "qemu/compiler.h" #include diff --git a/tests/unit/test-seccomp.c b/tests/unit/test-seccomp.c index 3d7771e46c..f02c79cafd 100644 --- a/tests/unit/test-seccomp.c +++ b/tests/unit/test-seccomp.c @@ -25,7 +25,6 @@ #include "qapi/error.h" #include "qemu/module.h" -#include #include static void test_seccomp_helper(const char *args, bool killed, diff --git a/ui/udmabuf.c b/ui/udmabuf.c index cebceb2610..cbf4357bb1 100644 --- a/ui/udmabuf.c +++ b/ui/udmabuf.c @@ -8,7 +8,6 @@ #include "qapi/error.h" #include "ui/console.h" -#include #include int udmabuf_fd(void) diff --git a/util/main-loop.c b/util/main-loop.c index 58f776a8c9..3c0f525192 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -33,7 +33,6 @@ #include "block/thread-pool.h" #include "qemu/error-report.h" #include "qemu/queue.h" -#include "qemu/compiler.h" #include "qom/object.h" #ifndef _WIN32 diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 59a891b6a8..fd03fd32c8 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -40,7 +40,6 @@ #include "qemu/thread.h" #include #include "qemu/cutils.h" -#include "qemu/compiler.h" #include "qemu/units.h" #include "qemu/thread-context.h" @@ -50,7 +49,6 @@ #ifdef __FreeBSD__ #include -#include #include #include #endif From a67dfa660b0dd944c8fedfac02806de75b0c08b1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Feb 2023 14:38:30 +0100 Subject: [PATCH 644/814] Drop duplicate #include Tracked down with the help of scripts/clean-includes. Signed-off-by: Markus Armbruster Acked-by: Dr. David Alan Gilbert Reviewed-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Reviewed-by: Juan Quintela Message-Id: <20230202133830.2152150-21-armbru@redhat.com> --- backends/tpm/tpm_emulator.c | 1 - hw/acpi/piix4.c | 1 - hw/alpha/dp264.c | 1 - hw/arm/virt.c | 1 - hw/arm/xlnx-versal.c | 1 - hw/block/pflash_cfi01.c | 1 - hw/core/machine.c | 1 - hw/hppa/machine.c | 1 - hw/i386/acpi-build.c | 1 - hw/loongarch/acpi-build.c | 1 - hw/misc/macio/cuda.c | 1 - hw/misc/macio/pmu.c | 1 - hw/net/xilinx_axienet.c | 1 - hw/ppc/ppc405_uc.c | 2 -- hw/ppc/ppc440_bamboo.c | 1 - hw/ppc/spapr_drc.c | 1 - hw/rdma/vmw/pvrdma_dev_ring.c | 1 - hw/remote/machine.c | 1 - hw/remote/remote-obj.c | 1 - hw/rtc/mc146818rtc.c | 1 - hw/s390x/virtio-ccw-serial.c | 1 - include/hw/arm/fsl-imx6ul.h | 1 - include/hw/arm/fsl-imx7.h | 1 - migration/postcopy-ram.c | 2 -- softmmu/dirtylimit.c | 1 - softmmu/runstate.c | 1 - softmmu/vl.c | 1 - target/loongarch/translate.c | 1 - target/mips/tcg/translate.c | 1 - target/nios2/translate.c | 2 -- tests/unit/test-cutils.c | 1 - ui/gtk.c | 1 - util/oslib-posix.c | 4 ---- 33 files changed, 39 deletions(-) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 67e7b212e3..d18144b92e 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -35,7 +35,6 @@ #include "sysemu/runstate.h" #include "sysemu/tpm_backend.h" #include "sysemu/tpm_util.h" -#include "sysemu/runstate.h" #include "tpm_int.h" #include "tpm_ioctl.h" #include "migration/blocker.h" diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 724294b378..eac2125abd 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -34,7 +34,6 @@ #include "sysemu/xen.h" #include "qapi/error.h" #include "qemu/range.h" -#include "hw/acpi/pcihp.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/acpi/cpu.h" #include "hw/hotplug.h" diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index c502c8c62a..4161f559a7 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -18,7 +18,6 @@ #include "net/net.h" #include "qemu/cutils.h" #include "qemu/datadir.h" -#include "net/net.h" static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ba47728288..75f28947de 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -33,7 +33,6 @@ #include "qemu/units.h" #include "qemu/option.h" #include "monitor/qdev.h" -#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/arm/primecell.h" diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 57276e1506..69b1b99e93 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -22,7 +22,6 @@ #include "hw/misc/unimp.h" #include "hw/arm/xlnx-versal.h" #include "qemu/log.h" -#include "hw/sysbus.h" #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") #define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f") diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 36d68c70f6..3c066e3405 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -45,7 +45,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/bitops.h" -#include "qemu/error-report.h" #include "qemu/host-utils.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/hw/core/machine.c b/hw/core/machine.c index b5cd42cd8c..f73fc4c45c 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -39,7 +39,6 @@ #include "exec/confidential-guest-support.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" -#include "qom/object_interfaces.h" GlobalProperty hw_compat_7_2[] = { { "virtio-mem", "x-early-migration", "false" }, diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index de1cc7ab71..7ac68c943f 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -28,7 +28,6 @@ #include "qapi/error.h" #include "net/net.h" #include "qemu/log.h" -#include "net/net.h" #define MIN_SEABIOS_HPPA_VERSION 6 /* require at least this fw version */ diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 145389aa58..b67dcbbb37 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -76,7 +76,6 @@ #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" -#include "hw/acpi/cxl.h" #include CONFIG_DEVICES diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index c2b237736d..f551296a0e 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -22,7 +22,6 @@ /* Supported chipsets: */ #include "hw/pci-host/ls7a.h" #include "hw/loongarch/virt.h" -#include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" #include "hw/acpi/pci.h" diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 7208b90e12..6336dcb194 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -28,7 +28,6 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "hw/misc/macio/cuda.h" -#include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/runstate.h" #include "sysemu/rtc.h" diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 8575bc1264..58316d1871 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -33,7 +33,6 @@ #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/misc/macio/pmu.h" -#include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/runstate.h" #include "sysemu/rtc.h" diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 7e00965323..5b19a01eaa 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -31,7 +31,6 @@ #include "net/net.h" #include "net/checksum.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/stream.h" diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index c973cfb04e..0cc68178ad 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -38,8 +38,6 @@ #include "sysemu/sysemu.h" #include "exec/address-spaces.h" #include "hw/intc/ppc-uic.h" -#include "hw/qdev-properties.h" -#include "qapi/error.h" #include "trace.h" /*****************************************************************************/ diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 81d71adf34..2880c81cb1 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/error-report.h" #include "qemu/datadir.h" #include "qemu/error-report.h" #include "net/net.h" diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 4923435a8b..b5c400a94d 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -17,7 +17,6 @@ #include "hw/ppc/spapr_drc.h" #include "qom/object.h" #include "migration/vmstate.h" -#include "qapi/error.h" #include "qapi/qapi-events-qdev.h" #include "qapi/visitor.h" #include "qemu/error-report.h" diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c index 598e6adc5e..30ce22a5be 100644 --- a/hw/rdma/vmw/pvrdma_dev_ring.c +++ b/hw/rdma/vmw/pvrdma_dev_ring.c @@ -14,7 +14,6 @@ */ #include "qemu/osdep.h" -#include "qemu/cutils.h" #include "hw/pci/pci.h" #include "cpu.h" #include "qemu/cutils.h" diff --git a/hw/remote/machine.c b/hw/remote/machine.c index 519f855ec1..fdc6c441bb 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -22,7 +22,6 @@ #include "hw/remote/iohub.h" #include "hw/remote/iommu.h" #include "hw/qdev-core.h" -#include "hw/remote/iommu.h" #include "hw/remote/vfio-user-obj.h" #include "hw/pci/msi.h" diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c index 333e5ac443..65b6f7cc86 100644 --- a/hw/remote/remote-obj.c +++ b/hw/remote/remote-obj.c @@ -12,7 +12,6 @@ #include "qemu/error-report.h" #include "qemu/notify.h" #include "qom/object_interfaces.h" -#include "hw/qdev-core.h" #include "io/channel.h" #include "hw/qdev-core.h" #include "hw/remote/machine.h" diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index bc1192b7ae..ba612a151d 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -43,7 +43,6 @@ #include "qapi/error.h" #include "qapi/qapi-events-misc.h" #include "qapi/visitor.h" -#include "hw/rtc/mc146818rtc_regs.h" //#define DEBUG_CMOS //#define DEBUG_COALESCED diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c index bf8057880f..8f8d2302f8 100644 --- a/hw/s390x/virtio-ccw-serial.c +++ b/hw/s390x/virtio-ccw-serial.c @@ -15,7 +15,6 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio-serial.h" #include "virtio-ccw.h" -#include "hw/virtio/virtio-serial.h" #define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw" OBJECT_DECLARE_SIMPLE_TYPE(VirtioSerialCcw, VIRTIO_SERIAL_CCW) diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 7812e516a5..1952cb984d 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -30,7 +30,6 @@ #include "hw/timer/imx_gpt.h" #include "hw/timer/imx_epit.h" #include "hw/i2c/imx_i2c.h" -#include "hw/gpio/imx_gpio.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" #include "hw/net/imx_fec.h" diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 4e5e071864..355bd8ea83 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -32,7 +32,6 @@ #include "hw/timer/imx_gpt.h" #include "hw/timer/imx_epit.h" #include "hw/i2c/imx_i2c.h" -#include "hw/gpio/imx_gpio.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" #include "hw/net/imx_fec.h" diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index b98e95dab0..53299b7a5e 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -17,7 +17,6 @@ */ #include "qemu/osdep.h" -#include "qemu/rcu.h" #include "qemu/madvise.h" #include "exec/target_page.h" #include "migration.h" @@ -34,7 +33,6 @@ #include "hw/boards.h" #include "exec/ramblock.h" #include "socket.h" -#include "qemu-file.h" #include "yank_functions.h" #include "tls.h" #include "qemu/userfaultfd.h" diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index 12668555f2..c56f0f58c8 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "qemu/main-loop.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qmp/qdict.h" diff --git a/softmmu/runstate.c b/softmmu/runstate.c index cab9f6fc07..f9ad88e6a7 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -41,7 +41,6 @@ #include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-events-run-state.h" #include "qemu/error-report.h" -#include "qemu/log.h" #include "qemu/job.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/softmmu/vl.c b/softmmu/vl.c index 5355a7fe5a..b2ee3fee3f 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -129,7 +129,6 @@ #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-visit-qom.h" #include "qapi/qapi-commands-ui.h" -#include "qapi/qmp/qdict.h" #include "block/qdict.h" #include "qapi/qmp/qerror.h" #include "sysemu/iothread.h" diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 38ced69803..72a6275665 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -12,7 +12,6 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" -#include "exec/translator.h" #include "exec/log.h" #include "qemu/qemu-print.h" #include "fpu/softfloat.h" diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 624e6b7786..aa12bb708a 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -32,7 +32,6 @@ #include "semihosting/semihost.h" #include "trace.h" -#include "exec/translator.h" #include "exec/log.h" #include "qemu/qemu-print.h" #include "fpu_helper.h" diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 4db8b47744..7aee65a089 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -938,8 +938,6 @@ static const char * const cr_regnames[NUM_CR_REGS] = { }; #endif -#include "exec/gen-icount.h" - /* generate intermediate code for basic block 'tb'. */ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 2126b46391..3c4f875420 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" #include "qemu/cutils.h" #include "qemu/units.h" diff --git a/ui/gtk.c b/ui/gtk.c index 4817623c8f..7f752d8b7d 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -53,7 +53,6 @@ #include #include "trace.h" -#include "qemu/cutils.h" #include "ui/input.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" diff --git a/util/oslib-posix.c b/util/oslib-posix.c index fd03fd32c8..77d882e681 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -59,10 +59,6 @@ #include "qemu/mmap-alloc.h" -#ifdef CONFIG_DEBUG_STACK_USAGE -#include "qemu/error-report.h" -#endif - #define MAX_MEM_PREALLOC_THREAD_COUNT 16 struct MemsetThread; From 65e57fdb25a0df8950f107041550aeb178af41ad Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:23 +0100 Subject: [PATCH 645/814] target/tricore: Fix OPC2_32_RCRW_IMASK translation we were mixing up the "c" and "d" registers. We used "d" as a destination register und "c" as the source. According to the TriCore ISA manual 1.6 vol 2 it is the other way round. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Resolves: https://gitlab.com/qemu-project/qemu/-/issues/653 Message-Id: <20230202120432.1268-2-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index df9e46c649..8de4e56b1f 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5794,11 +5794,11 @@ static void decode_rcrw_insert(DisasContext *ctx) switch (op2) { case OPC2_32_RCRW_IMASK: - tcg_gen_andi_tl(temp, cpu_gpr_d[r4], 0x1f); + tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f); tcg_gen_movi_tl(temp2, (1 << width) - 1); - tcg_gen_shl_tl(cpu_gpr_d[r3 + 1], temp2, temp); + tcg_gen_shl_tl(cpu_gpr_d[r4 + 1], temp2, temp); tcg_gen_movi_tl(temp2, const4); - tcg_gen_shl_tl(cpu_gpr_d[r3], temp2, temp); + tcg_gen_shl_tl(cpu_gpr_d[r4], temp2, temp); break; case OPC2_32_RCRW_INSERT: temp3 = tcg_temp_new(); From 76f7f54840abef8f712e51d87ecb38f27a0d9db0 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:24 +0100 Subject: [PATCH 646/814] tests/tcg/tricore: Add test for OPC2_32_RCRW_IMASK Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-3-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/macros.h | 7 +++++++ tests/tcg/tricore/test_imask.S | 10 ++++++++++ 3 files changed, 18 insertions(+) create mode 100644 tests/tcg/tricore/test_imask.S diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index 5007c60ce8..bc0cfae8d0 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -10,6 +10,7 @@ TESTS += test_dvstep.tst TESTS += test_fadd.tst TESTS += test_fmul.tst TESTS += test_ftoi.tst +TESTS += test_imask.tst TESTS += test_madd.tst TESTS += test_msub.tst TESTS += test_muls.tst diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index 0d76fc403a..ceb7e9c0b7 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -111,6 +111,13 @@ test_ ## num: \ insn EREG_CALC_RESULT, EREG_RS1, DREG_RS2; \ ) +#define TEST_E_IDI(insn, num, res_hi, res_lo, imm1, rs1, imm2) \ + TEST_CASE_E(num, res_lo, res_hi, \ + LI(DREG_RS1, rs1); \ + rstv; \ + insn EREG_CALC_RESULT, imm1, DREG_RS1, imm2); \ + ) + /* Pass/Fail handling part */ #define TEST_PASSFAIL \ j pass; \ diff --git a/tests/tcg/tricore/test_imask.S b/tests/tcg/tricore/test_imask.S new file mode 100644 index 0000000000..356cf398b8 --- /dev/null +++ b/tests/tcg/tricore/test_imask.S @@ -0,0 +1,10 @@ +#include "macros.h" +.text +.global _start +_start: +# res[31:0] +# insn num res[63:32] | imm1 rs1 imm2 +# | | | | | | | + TEST_E_IDI(imask, 1, 0x000f0000, 0x00050000, 0x5, 0x10, 0x4) + + TEST_PASSFAIL From 1c6b2e4b794d460a16a7f94cf6a7d6864f708be1 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:25 +0100 Subject: [PATCH 647/814] target/tricore: Fix OPC2_32_RCRW_INSERT translation we were mixing up the "c" and "d" registers. We used "d" as a destination register und "c" as the source. According to the TriCore ISA manual 1.6 vol 2 it is the other way round. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Resolves: https://gitlab.com/qemu-project/qemu/-/issues/653 Message-Id: <20230202120432.1268-4-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 8de4e56b1f..6149d4f5c0 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5805,8 +5805,8 @@ static void decode_rcrw_insert(DisasContext *ctx) tcg_gen_movi_tl(temp, width); tcg_gen_movi_tl(temp2, const4); - tcg_gen_andi_tl(temp3, cpu_gpr_d[r4], 0x1f); - gen_insert(cpu_gpr_d[r3], cpu_gpr_d[r1], temp2, temp, temp3); + tcg_gen_andi_tl(temp3, cpu_gpr_d[r3], 0x1f); + gen_insert(cpu_gpr_d[r4], cpu_gpr_d[r1], temp2, temp, temp3); tcg_temp_free(temp3); break; From fa581531ffdc94ba18da6ec0c566bece57a60a85 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:26 +0100 Subject: [PATCH 648/814] tests/tcg/tricore: Add test for OPC2_32_RCRW_INSERT DREG_RS2 and DREG_CALC_RESULT were mapped to the same register which would not trigger https://gitlab.com/qemu-project/qemu/-/issues/653. So let's make each register unique. Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-5-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/macros.h | 16 ++++++++++++---- tests/tcg/tricore/test_insert.S | 9 +++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 tests/tcg/tricore/test_insert.S diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index bc0cfae8d0..afabba8631 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -11,6 +11,7 @@ TESTS += test_fadd.tst TESTS += test_fmul.tst TESTS += test_ftoi.tst TESTS += test_imask.tst +TESTS += test_insert.tst TESTS += test_madd.tst TESTS += test_msub.tst TESTS += test_muls.tst diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index ceb7e9c0b7..4f2bc3cb0f 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -9,10 +9,10 @@ /* Register definitions */ #define DREG_RS1 %d0 #define DREG_RS2 %d1 -#define DREG_RS3 %d4 -#define DREG_CALC_RESULT %d1 -#define DREG_CALC_PSW %d2 -#define DREG_CORRECT_PSW %d3 +#define DREG_RS3 %d2 +#define DREG_CALC_RESULT %d3 +#define DREG_CALC_PSW %d4 +#define DREG_CORRECT_PSW %d5 #define DREG_TEMP_LI %d10 #define DREG_TEMP %d11 #define DREG_TEST_NUM %d14 @@ -103,6 +103,14 @@ test_ ## num: \ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm; \ ) +#define TEST_D_DIDI(insn, num, result, rs1, imm1, rs2, imm2) \ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs1); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, imm1, DREG_RS2, imm2; \ + ) + #define TEST_E_ED(insn, num, res_hi, res_lo, rs1_hi, rs1_lo, rs2) \ TEST_CASE_E(num, res_lo, res_hi, \ LI(EREG_RS1_LO, rs1_lo); \ diff --git a/tests/tcg/tricore/test_insert.S b/tests/tcg/tricore/test_insert.S new file mode 100644 index 0000000000..d5fd2237e1 --- /dev/null +++ b/tests/tcg/tricore/test_insert.S @@ -0,0 +1,9 @@ +#include "macros.h" +.text +.global _start +_start: +# insn num result rs1 imm1 rs2 imm2 +# | | | | | | | + TEST_D_DIDI(insert, 1, 0x7fffffff, 0xffffffff, 0xa, 0x10, 0x8) + + TEST_PASSFAIL From 48bffe7f6b65e78d84ffae0e4385af1aa935767c Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:27 +0100 Subject: [PATCH 649/814] target/tricore: Fix RRPW_DEXTR if we used const16 == 0 we would crash qemu with the error: ../tcg/tcg-op.c:196: tcg_gen_shri_i32: Assertion `arg2 >= 0 && arg2 < 32' failed This whole instruction can be handled by 'tcg_gen_extract2_tl' which takes care of this special case as well. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-6-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6149d4f5c0..3b4ec530b1 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8706,15 +8706,9 @@ static void decode_32Bit_opc(DisasContext *ctx) r2 = MASK_OP_RRPW_S2(ctx->opcode); r3 = MASK_OP_RRPW_D(ctx->opcode); const16 = MASK_OP_RRPW_POS(ctx->opcode); - if (r1 == r2) { - tcg_gen_rotli_tl(cpu_gpr_d[r3], cpu_gpr_d[r1], const16); - } else { - temp = tcg_temp_new(); - tcg_gen_shli_tl(temp, cpu_gpr_d[r1], const16); - tcg_gen_shri_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], 32 - const16); - tcg_gen_or_tl(cpu_gpr_d[r3], cpu_gpr_d[r3], temp); - tcg_temp_free(temp); - } + + tcg_gen_extract2_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], cpu_gpr_d[r1], + 32 - const16); break; /* RRR Format */ case OPCM_32_RRR_COND_SELECT: From 70447df9365c9401643e4260436c64b35aab003e Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:28 +0100 Subject: [PATCH 650/814] tests/tcg/tricore: Add tests for RRPW_DEXTR Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-7-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/macros.h | 8 +++++ tests/tcg/tricore/test_dextr.S | 40 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 tests/tcg/tricore/test_dextr.S diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index afabba8631..e83cc4b7cd 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -6,6 +6,7 @@ ASFLAGS = TESTS += test_abs.tst TESTS += test_bmerge.tst TESTS += test_clz.tst +TESTS += test_dextr.tst TESTS += test_dvstep.tst TESTS += test_fadd.tst TESTS += test_fmul.tst diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index 4f2bc3cb0f..8bc0faf1e4 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -95,6 +95,14 @@ test_ ## num: \ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, DREG_RS3; \ ) +#define TEST_D_DDI(insn, num, result, rs1, rs2, imm) \ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm; \ + ) + #define TEST_D_DDI_PSW(insn, num, result, psw, rs1, rs2, imm) \ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ LI(DREG_RS1, rs1); \ diff --git a/tests/tcg/tricore/test_dextr.S b/tests/tcg/tricore/test_dextr.S new file mode 100644 index 0000000000..c8a9fc453a --- /dev/null +++ b/tests/tcg/tricore/test_dextr.S @@ -0,0 +1,40 @@ +#include "macros.h" +.text +.global _start +_start: +# insn num result rs1 rs2 imm +# | | | | | | + TEST_D_DDI(dextr, 1, 0xabcdef01, 0xabcdef01, 0x23456789, 0) + TEST_D_DDI(dextr, 2, 0x579bde02, 0xabcdef01, 0x23456789, 1) + TEST_D_DDI(dextr, 3, 0xaf37bc04, 0xabcdef01, 0x23456789, 2) + TEST_D_DDI(dextr, 4, 0x5e6f7809, 0xabcdef01, 0x23456789, 3) + TEST_D_DDI(dextr, 5, 0xbcdef012, 0xabcdef01, 0x23456789, 4) + TEST_D_DDI(dextr, 6, 0x79bde024, 0xabcdef01, 0x23456789, 5) + TEST_D_DDI(dextr, 7, 0xf37bc048, 0xabcdef01, 0x23456789, 6) + TEST_D_DDI(dextr, 8, 0xe6f78091, 0xabcdef01, 0x23456789, 7) + TEST_D_DDI(dextr, 9, 0xcdef0123, 0xabcdef01, 0x23456789, 8) + TEST_D_DDI(dextr, 10, 0x9bde0246, 0xabcdef01, 0x23456789, 9) + TEST_D_DDI(dextr, 11, 0x37bc048d, 0xabcdef01, 0x23456789, 10) + TEST_D_DDI(dextr, 12, 0x6f78091a, 0xabcdef01, 0x23456789, 11) + TEST_D_DDI(dextr, 13, 0xdef01234, 0xabcdef01, 0x23456789, 12) + TEST_D_DDI(dextr, 14, 0xbde02468, 0xabcdef01, 0x23456789, 13) + TEST_D_DDI(dextr, 15, 0x7bc048d1, 0xabcdef01, 0x23456789, 14) + TEST_D_DDI(dextr, 16, 0xf78091a2, 0xabcdef01, 0x23456789, 15) + TEST_D_DDI(dextr, 17, 0xef012345, 0xabcdef01, 0x23456789, 16) + TEST_D_DDI(dextr, 18, 0xde02468a, 0xabcdef01, 0x23456789, 17) + TEST_D_DDI(dextr, 19, 0xbc048d15, 0xabcdef01, 0x23456789, 18) + TEST_D_DDI(dextr, 20, 0x78091a2b, 0xabcdef01, 0x23456789, 19) + TEST_D_DDI(dextr, 21, 0xf0123456, 0xabcdef01, 0x23456789, 20) + TEST_D_DDI(dextr, 22, 0xe02468ac, 0xabcdef01, 0x23456789, 21) + TEST_D_DDI(dextr, 23, 0xc048d159, 0xabcdef01, 0x23456789, 22) + TEST_D_DDI(dextr, 24, 0x8091a2b3, 0xabcdef01, 0x23456789, 23) + TEST_D_DDI(dextr, 25, 0x01234567, 0xabcdef01, 0x23456789, 24) + TEST_D_DDI(dextr, 26, 0x02468acf, 0xabcdef01, 0x23456789, 25) + TEST_D_DDI(dextr, 27, 0x048d159e, 0xabcdef01, 0x23456789, 26) + TEST_D_DDI(dextr, 28, 0x091a2b3c, 0xabcdef01, 0x23456789, 27) + TEST_D_DDI(dextr, 29, 0x12345678, 0xabcdef01, 0x23456789, 28) + TEST_D_DDI(dextr, 30, 0x2468acf1, 0xabcdef01, 0x23456789, 29) + TEST_D_DDI(dextr, 31, 0x48d159e2, 0xabcdef01, 0x23456789, 30) + TEST_D_DDI(dextr, 32, 0x91a2b3c4, 0xabcdef01, 0x23456789, 31) + + TEST_PASSFAIL From a4d5d153c4c53076cea70c1609f3d7427322586b Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:29 +0100 Subject: [PATCH 651/814] target/tricore: Fix OPC2_32_RRRR_DEXTR if cpu_gpr_d[r3] == 0 then we were shifting the lower register to the right by 32 which is undefined behaviour. In this case the TriCore would do nothing an just return the higher register cpu_reg_d[r1]. We fixed that by detecting whether cpu_gpr_d[r3] was zero and cleared the lower register. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-8-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 3b4ec530b1..8bf78b46d0 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -8245,10 +8245,19 @@ static void decode_rrrr_extract_insert(DisasContext *ctx) if (r1 == r2) { tcg_gen_rotl_tl(cpu_gpr_d[r4], cpu_gpr_d[r1], tmp_pos); } else { + TCGv msw = tcg_temp_new(); + TCGv zero = tcg_constant_tl(0); tcg_gen_shl_tl(tmp_width, cpu_gpr_d[r1], tmp_pos); - tcg_gen_subfi_tl(tmp_pos, 32, tmp_pos); - tcg_gen_shr_tl(tmp_pos, cpu_gpr_d[r2], tmp_pos); - tcg_gen_or_tl(cpu_gpr_d[r4], tmp_width, tmp_pos); + tcg_gen_subfi_tl(msw, 32, tmp_pos); + tcg_gen_shr_tl(msw, cpu_gpr_d[r2], msw); + /* + * if pos == 0, then we do cpu_gpr_d[r2] << 32, which is undefined + * behaviour. So check that case here and set the low bits to zero + * which effectivly returns cpu_gpr_d[r1] + */ + tcg_gen_movcond_tl(TCG_COND_EQ, msw, tmp_pos, zero, zero, msw); + tcg_gen_or_tl(cpu_gpr_d[r4], tmp_width, msw); + tcg_temp_free(msw); } break; case OPC2_32_RRRR_EXTR: From 7ebe4cb36433af7aaaf621e851784f89b8cc5cb8 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:30 +0100 Subject: [PATCH 652/814] tests/tcg/tricore: Add OPC2_32_RRRR_DEXTR tests Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-9-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/macros.h | 9 +++++++++ tests/tcg/tricore/test_dextr.S | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index 8bc0faf1e4..06bdbf83cb 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -78,6 +78,15 @@ test_ ## num: \ insn DREG_CORRECT_RESULT, DREG_RS1; \ ) +#define TEST_D_DDD(insn, num, result, rs1, rs2, rs3) \ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + LI(DREG_RS3, rs3); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, DREG_RS3; \ + ) + #define TEST_D_DD_PSW(insn, num, result, psw, rs1, rs2) \ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ LI(DREG_RS1, rs1); \ diff --git a/tests/tcg/tricore/test_dextr.S b/tests/tcg/tricore/test_dextr.S index c8a9fc453a..82c8fe5185 100644 --- a/tests/tcg/tricore/test_dextr.S +++ b/tests/tcg/tricore/test_dextr.S @@ -37,4 +37,39 @@ _start: TEST_D_DDI(dextr, 31, 0x48d159e2, 0xabcdef01, 0x23456789, 30) TEST_D_DDI(dextr, 32, 0x91a2b3c4, 0xabcdef01, 0x23456789, 31) +# insn num result rs1 rs2 rs3 +# | | | | | | + TEST_D_DDD(dextr, 33, 0xabcdef01, 0xabcdef01, 0x23456789, 0) + TEST_D_DDD(dextr, 34, 0x579bde02, 0xabcdef01, 0x23456789, 1) + TEST_D_DDD(dextr, 35, 0xaf37bc04, 0xabcdef01, 0x23456789, 2) + TEST_D_DDD(dextr, 36, 0x5e6f7809, 0xabcdef01, 0x23456789, 3) + TEST_D_DDD(dextr, 37, 0xbcdef012, 0xabcdef01, 0x23456789, 4) + TEST_D_DDD(dextr, 38, 0x79bde024, 0xabcdef01, 0x23456789, 5) + TEST_D_DDD(dextr, 39, 0xf37bc048, 0xabcdef01, 0x23456789, 6) + TEST_D_DDD(dextr, 40, 0xe6f78091, 0xabcdef01, 0x23456789, 7) + TEST_D_DDD(dextr, 41, 0xcdef0123, 0xabcdef01, 0x23456789, 8) + TEST_D_DDD(dextr, 42, 0x9bde0246, 0xabcdef01, 0x23456789, 9) + TEST_D_DDD(dextr, 43, 0x37bc048d, 0xabcdef01, 0x23456789, 10) + TEST_D_DDD(dextr, 44, 0x6f78091a, 0xabcdef01, 0x23456789, 11) + TEST_D_DDD(dextr, 45, 0xdef01234, 0xabcdef01, 0x23456789, 12) + TEST_D_DDD(dextr, 46, 0xbde02468, 0xabcdef01, 0x23456789, 13) + TEST_D_DDD(dextr, 47, 0x7bc048d1, 0xabcdef01, 0x23456789, 14) + TEST_D_DDD(dextr, 48, 0xf78091a2, 0xabcdef01, 0x23456789, 15) + TEST_D_DDD(dextr, 49, 0xef012345, 0xabcdef01, 0x23456789, 16) + TEST_D_DDD(dextr, 51, 0xde02468a, 0xabcdef01, 0x23456789, 17) + TEST_D_DDD(dextr, 52, 0xbc048d15, 0xabcdef01, 0x23456789, 18) + TEST_D_DDD(dextr, 53, 0x78091a2b, 0xabcdef01, 0x23456789, 19) + TEST_D_DDD(dextr, 54, 0xf0123456, 0xabcdef01, 0x23456789, 20) + TEST_D_DDD(dextr, 55, 0xe02468ac, 0xabcdef01, 0x23456789, 21) + TEST_D_DDD(dextr, 56, 0xc048d159, 0xabcdef01, 0x23456789, 22) + TEST_D_DDD(dextr, 57, 0x8091a2b3, 0xabcdef01, 0x23456789, 23) + TEST_D_DDD(dextr, 58, 0x01234567, 0xabcdef01, 0x23456789, 24) + TEST_D_DDD(dextr, 59, 0x02468acf, 0xabcdef01, 0x23456789, 25) + TEST_D_DDD(dextr, 60, 0x048d159e, 0xabcdef01, 0x23456789, 26) + TEST_D_DDD(dextr, 61, 0x091a2b3c, 0xabcdef01, 0x23456789, 27) + TEST_D_DDD(dextr, 62, 0x12345678, 0xabcdef01, 0x23456789, 28) + TEST_D_DDD(dextr, 63, 0x2468acf1, 0xabcdef01, 0x23456789, 29) + TEST_D_DDD(dextr, 64, 0x48d159e2, 0xabcdef01, 0x23456789, 30) + TEST_D_DDD(dextr, 65, 0x91a2b3c4, 0xabcdef01, 0x23456789, 31) + TEST_PASSFAIL From d8b33554d8dd9ee6348839d9e4d6f93adf45eff1 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:31 +0100 Subject: [PATCH 653/814] target/tricore: Fix OPC2_32_BO_LD_BU_PREINC we were sign extending the result of the load, while the instruction clearly states that the result should be unsigned. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-10-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 8bf78b46d0..ab386cef50 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -4964,7 +4964,7 @@ static void decode_bo_addrmode_ld_post_pre_base(DisasContext *ctx) tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10); break; case OPC2_32_BO_LD_BU_PREINC: - gen_ld_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_SB); + gen_ld_preincr(ctx, cpu_gpr_d[r1], cpu_gpr_a[r2], off10, MO_UB); break; case OPC2_32_BO_LD_D_SHORTOFF: CHECK_REG_PAIR(r1); From 6dcb9922f3dd6d7f7129621f7a10acead32dcbb0 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 2 Feb 2023 13:04:32 +0100 Subject: [PATCH 654/814] tests/tcg/tricore: Add LD.BU tests Signed-off-by: Bastian Koppelmann Message-Id: <20230202120432.1268-11-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/macros.h | 23 +++++++++++++++++++++++ tests/tcg/tricore/test_ld_bu.S | 15 +++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/tcg/tricore/test_ld_bu.S diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index e83cc4b7cd..b6c19dbecd 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -13,6 +13,7 @@ TESTS += test_fmul.tst TESTS += test_ftoi.tst TESTS += test_imask.tst TESTS += test_insert.tst +TESTS += test_ld_bu.tst TESTS += test_madd.tst TESTS += test_msub.tst TESTS += test_muls.tst diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index 06bdbf83cb..109ef62a4d 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -4,6 +4,10 @@ movh DREG_TEMP_LI, up:val; \ or reg, reg, DREG_TEMP_LI; \ +#define LIA(reg, val) \ + LI(DREG_TEMP, val) \ + mov.a reg, DREG_TEMP; + /* Address definitions */ #define TESTDEV_ADDR 0xf0000000 /* Register definitions */ @@ -18,6 +22,10 @@ #define DREG_TEST_NUM %d14 #define DREG_CORRECT_RESULT %d15 +#define AREG_ADDR %a0 +#define AREG_CORRECT_RESULT %a3 +#define MEM_BASE_ADDR 0xd0000000 + #define DREG_DEV_ADDR %a15 #define EREG_RS1 %e6 @@ -60,11 +68,24 @@ test_ ## num: \ mov DREG_TEST_NUM, num; \ jne DREG_CALC_PSW, DREG_CORRECT_PSW, fail; +#define TEST_LD(insn, num, result, addr_result, ld_pattern) \ +test_ ## num: \ + LIA(AREG_ADDR, test_data) \ + insn DREG_CALC_RESULT, ld_pattern; \ + LI(DREG_CORRECT_RESULT, result) \ + mov DREG_TEST_NUM, num; \ + jne DREG_CALC_RESULT, DREG_CORRECT_RESULT, fail; \ + mov.d DREG_CALC_RESULT, AREG_ADDR; \ + LI(DREG_CORRECT_RESULT, addr_result) \ + jne DREG_CALC_RESULT, DREG_CORRECT_RESULT, fail; + /* Actual test case type * e.g inst %dX, %dY -> TEST_D_D * inst %dX, %dY, %dZ -> TEST_D_DD * inst %eX, %dY, %dZ -> TEST_E_DD */ + + #define TEST_D_D(insn, num, result, rs1) \ TEST_CASE(num, DREG_CALC_RESULT, result, \ LI(DREG_RS1, rs1); \ @@ -143,6 +164,8 @@ test_ ## num: \ insn EREG_CALC_RESULT, imm1, DREG_RS1, imm2); \ ) + + /* Pass/Fail handling part */ #define TEST_PASSFAIL \ j pass; \ diff --git a/tests/tcg/tricore/test_ld_bu.S b/tests/tcg/tricore/test_ld_bu.S new file mode 100644 index 0000000000..ff9dac128b --- /dev/null +++ b/tests/tcg/tricore/test_ld_bu.S @@ -0,0 +1,15 @@ +#include "macros.h" +.data +test_data: + .word 0xaffedead + .word 0x001122ff +.text +.global _start +_start: +# expect. addr reg val after load +# insn num expect. load value | pattern for loading +# | | | | | + TEST_LD(ld.bu, 1, 0xff, MEM_BASE_ADDR + 4, [+AREG_ADDR]4) # pre_inc + TEST_LD(ld.bu, 2, 0xad, MEM_BASE_ADDR + 4, [AREG_ADDR+]4) # post_inc + + TEST_PASSFAIL From 77eb0085c8fe48e77f845d9db0d3c4c4ccf7c4f1 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 12 Jan 2023 14:24:02 +0000 Subject: [PATCH 655/814] target/tricore: Fix OPC1_16_SRO_LD_H translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bastian Koppelmann Signed-off-by: Eitan Eliahu Resolves: https://gitlab.com/qemu-project/qemu/-/issues/652 Message-Id: <20230112142258.514079-1-anton.kochkov@proton.me> Signed-off-by: Bastian Koppelmann --- target/tricore/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index ab386cef50..7ac34efd76 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -3878,7 +3878,7 @@ static void decode_sro_opc(DisasContext *ctx, int op1) gen_offset_ld(ctx, cpu_gpr_d[15], cpu_gpr_a[r2], address, MO_UB); break; case OPC1_16_SRO_LD_H: - gen_offset_ld(ctx, cpu_gpr_d[15], cpu_gpr_a[r2], address, MO_LESW); + gen_offset_ld(ctx, cpu_gpr_d[15], cpu_gpr_a[r2], address * 2, MO_LESW); break; case OPC1_16_SRO_LD_W: gen_offset_ld(ctx, cpu_gpr_d[15], cpu_gpr_a[r2], address * 4, MO_LESL); From 6e34f54d88184b25db4fbc4dd1665d9be1a9e21c Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Fri, 3 Feb 2023 14:21:32 +0100 Subject: [PATCH 656/814] tests/tcg/tricore: Add test for ld.h this exercises the error reported in https://gitlab.com/qemu-project/qemu/-/issues/652. Signed-off-by: Bastian Koppelmann Message-Id: <20230203132132.511254-1-kbastian@mail.uni-paderborn.de> Signed-off-by: Bastian Koppelmann --- tests/tcg/tricore/Makefile.softmmu-target | 1 + tests/tcg/tricore/macros.h | 13 +++++++++++++ tests/tcg/tricore/test_ld_h.S | 15 +++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 tests/tcg/tricore/test_ld_h.S diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target index b6c19dbecd..d2446af8b4 100644 --- a/tests/tcg/tricore/Makefile.softmmu-target +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -14,6 +14,7 @@ TESTS += test_ftoi.tst TESTS += test_imask.tst TESTS += test_insert.tst TESTS += test_ld_bu.tst +TESTS += test_ld_h.tst TESTS += test_madd.tst TESTS += test_msub.tst TESTS += test_muls.tst diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h index 109ef62a4d..ec4f5bff52 100644 --- a/tests/tcg/tricore/macros.h +++ b/tests/tcg/tricore/macros.h @@ -21,6 +21,7 @@ #define DREG_TEMP %d11 #define DREG_TEST_NUM %d14 #define DREG_CORRECT_RESULT %d15 +#define DREG_CORRECT_RESULT_2 %d13 #define AREG_ADDR %a0 #define AREG_CORRECT_RESULT %a3 @@ -79,6 +80,18 @@ test_ ## num: \ LI(DREG_CORRECT_RESULT, addr_result) \ jne DREG_CALC_RESULT, DREG_CORRECT_RESULT, fail; +#define TEST_LD_SRO(insn, num, result, addr_result, ld_pattern) \ +test_ ## num: \ + LIA(AREG_ADDR, test_data) \ + insn %d15, ld_pattern; \ + LI(DREG_CORRECT_RESULT_2, result) \ + mov DREG_TEST_NUM, num; \ + jne %d15, DREG_CORRECT_RESULT_2, fail; \ + mov.d DREG_CALC_RESULT, AREG_ADDR; \ + LI(DREG_CORRECT_RESULT, addr_result) \ + jne DREG_CALC_RESULT, DREG_CORRECT_RESULT, fail; + + /* Actual test case type * e.g inst %dX, %dY -> TEST_D_D * inst %dX, %dY, %dZ -> TEST_D_DD diff --git a/tests/tcg/tricore/test_ld_h.S b/tests/tcg/tricore/test_ld_h.S new file mode 100644 index 0000000000..d3c157a046 --- /dev/null +++ b/tests/tcg/tricore/test_ld_h.S @@ -0,0 +1,15 @@ +#include "macros.h" +.data +test_data: + .word 0xaffedead + .word 0x001122ff +.text +.global _start +_start: +# expect. addr reg val after load +# insn num expect. load value | pattern for loading +# | | | | | + TEST_LD (ld.h, 1, 0xffffaffe, MEM_BASE_ADDR, [AREG_ADDR]2) + TEST_LD_SRO(ld.h, 2, 0x000022ff, MEM_BASE_ADDR, [AREG_ADDR]4) + + TEST_PASSFAIL From 417296c8d8588f782018d01a317f88957e9786d6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Feb 2023 16:51:19 +0000 Subject: [PATCH 657/814] tests/qtest/netdev-socket: Raise connection timeout to 60 seconds The netdev-socket test intermittently fails on our s390x CI runner: 633/659 ERROR:../tests/qtest/netdev-socket.c:197:test_stream_unix: assertion failed (resp == expect): ("st0: index=0,type=stream,connection error\r\n" == "st0: index=0,type=stream,unix:/tmp/netdev-socket.GZUG01/stream_unix\r\n") ERROR 633/659 qemu:qtest+qtest-xtensa / qtest-xtensa/netdev-socket ERROR 5.47s killed by signal 6 SIGABRT This may just be because when the machine is under heavy load running the CI tests it hits the timeout before the QEMU under test has started to the point of being able to respond to HMP queries. Bump the timeout to 60 seconds to see if the intermittent goes away. Acked-by: Thomas Huth Signed-off-by: Peter Maydell Message-id: 20230207165119.1479132-1-peter.maydell@linaro.org --- tests/qtest/netdev-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c index 6ba256e173..1d98dca821 100644 --- a/tests/qtest/netdev-socket.c +++ b/tests/qtest/netdev-socket.c @@ -12,7 +12,7 @@ #include "../unit/socket-helpers.h" #include "libqtest.h" -#define CONNECTION_TIMEOUT 5 +#define CONNECTION_TIMEOUT 60 #define EXPECT_STATE(q, e, t) \ do { \ From 331acddc87b739c64b936ba4e58518f8491f1c6b Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 30 Jan 2023 23:02:25 +0900 Subject: [PATCH 658/814] vhost-user-fs: Back up vqs before cleaning up vhost_dev vhost_dev_cleanup() clears vhost_dev so back up its vqs member to free the memory pointed by the member. Fixes: 98fc1ada4c ("virtio: add vhost-user-fs base device") Signed-off-by: Akihiko Odaki Signed-off-by: Stefan Hajnoczi Message-Id: <20230130140225.77964-1-akihiko.odaki@daynix.com> --- hw/virtio/vhost-user-fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index f5049735ac..83fc20e49e 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -273,6 +273,7 @@ static void vuf_device_unrealize(DeviceState *dev) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserFS *fs = VHOST_USER_FS(dev); + struct vhost_virtqueue *vhost_vqs = fs->vhost_dev.vqs; int i; /* This will stop vhost backend if appropriate. */ @@ -288,8 +289,7 @@ static void vuf_device_unrealize(DeviceState *dev) } g_free(fs->req_vqs); virtio_cleanup(vdev); - g_free(fs->vhost_dev.vqs); - fs->vhost_dev.vqs = NULL; + g_free(vhost_vqs); } static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev) From 1f433e84c3f3ddda90ba235e65b99ef1112f48c7 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Wed, 8 Feb 2023 06:11:48 -0500 Subject: [PATCH 659/814] virtio-blk: add missing AioContext lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_blk_update_config() calls blk_get_geometry and blk_getlength, and both functions eventually end up calling bdrv_poll_co when not running in a coroutine: - blk_getlength is a co_wrapper_mixed function - blk_get_geometry calls bdrv_get_geometry -> bdrv_nb_sectors, a co_wrapper_mixed function too Since we are not running in a coroutine, we need to take s->blk AioContext lock, otherwise bdrv_poll_co will inevitably call AIO_WAIT_WHILE and therefore try to un unlock() an AioContext lock that was never acquired. RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=2167838 Steps to reproduce the issue: simply boot a VM with -object '{"qom-type":"iothread","id":"iothread1"}' \ -blockdev '{"driver":"file","filename":"$QCOW2","aio":"native","node-name":"libvirt-1-storage","cache":{"direct":true,"no-flush":false},"auto-read-only":true,"discard":"unmap"}' \ -blockdev '{"node-name":"libvirt-1-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-1-storage"}' \ -device virtio-blk-pci,iothread=iothread1,drive=libvirt-1-format,id=virtio-disk0,bootindex=1,write-cache=on and observe that it will fail not manage to boot with "qemu_mutex_unlock_impl: Operation not permitted" Signed-off-by: Emanuele Giuseppe Esposito Acked-by: Michael S. Tsirkin Tested-by: Lukáš Doktor Signed-off-by: Stefan Hajnoczi Message-Id: <20230208111148.1040083-1-eesposit@redhat.com> --- hw/block/virtio-blk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 1762517878..cefca93b31 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -894,6 +894,10 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) uint64_t capacity; int64_t length; int blk_size = conf->logical_block_size; + AioContext *ctx; + + ctx = blk_get_aio_context(s->blk); + aio_context_acquire(ctx); blk_get_geometry(s->blk, &capacity); memset(&blkcfg, 0, sizeof(blkcfg)); @@ -917,6 +921,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) * per track (cylinder). */ length = blk_getlength(s->blk); + aio_context_release(ctx); if (length > 0 && length / conf->heads / conf->secs % blk_size) { blkcfg.geometry.sectors = conf->secs & ~s->sector_mask; } else { From 3c5867156eb81c7c71611d078b2c5c2c863f884a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 7 Feb 2023 15:37:16 -0500 Subject: [PATCH 660/814] block: fix detect-zeroes= with BDRV_REQ_REGISTERED_BUF When a write request is converted into a write zeroes request by the detect-zeroes= feature, it is no longer associated with an I/O buffer. The BDRV_REQ_REGISTERED_BUF flag doesn't make sense without an I/O buffer and must be cleared because bdrv_co_do_pwrite_zeroes() fails with -EINVAL when it's set. Fiona Ebner bisected and diagnosed this QEMU 7.2 regression where writes containing zeroes to a blockdev with discard=unmap,detect-zeroes=unmap fail. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1404 Fixes: e8b6535533be ("block: add BDRV_REQ_REGISTERED_BUF request flag") Tested-by: Fiona Ebner Cc: qemu-stable@nongnu.org Reviewed-by: Eric Blake Reviewed-by: Hanna Czenczek Signed-off-by: Stefan Hajnoczi Message-Id: <20230207203719.242926-2-stefanha@redhat.com> --- block/io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/io.c b/block/io.c index 2dc0c13e41..d2be37b11e 100644 --- a/block/io.c +++ b/block/io.c @@ -1926,6 +1926,9 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) { flags |= BDRV_REQ_MAY_UNMAP; } + + /* Can't use optimization hint with bufferless zero write */ + flags &= ~BDRV_REQ_REGISTERED_BUF; } if (ret < 0) { From 1321e00801bc26ff8059e8513f3ae3f7265d24f6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 7 Feb 2023 15:37:17 -0500 Subject: [PATCH 661/814] qemu-io: use BdrvRequestFlags instead of int The block layer APIs use BdrvRequestFlags while qemu-io code uses int. Although the code compiles and runs fine, BdrvRequestFlags is clearer because it differentiates between other types of flags like bdrv_open() flags. This is purely refactoring. Reviewed-by: Eric Blake Reviewed-by: Hanna Czenczek Signed-off-by: Stefan Hajnoczi Message-Id: <20230207203719.242926-3-stefanha@redhat.com> --- qemu-io-cmds.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index a061031615..1f60c23ba4 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -556,7 +556,7 @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset, } static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, - int64_t bytes, int flags, int64_t *total) + int64_t bytes, BdrvRequestFlags flags, int64_t *total) { int ret; @@ -573,7 +573,8 @@ static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, } static int do_pwrite_zeroes(BlockBackend *blk, int64_t offset, - int64_t bytes, int flags, int64_t *total) + int64_t bytes, BdrvRequestFlags flags, + int64_t *total) { int ret = blk_pwrite_zeroes(blk, offset, bytes, flags | BDRV_REQ_ZERO_WRITE); @@ -651,7 +652,7 @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov, } static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov, - int64_t offset, int flags, int *total) + int64_t offset, BdrvRequestFlags flags, int *total) { int async_ret = NOT_DONE; @@ -1028,7 +1029,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) struct timespec t1, t2; bool Cflag = false, qflag = false, bflag = false; bool Pflag = false, zflag = false, cflag = false, sflag = false; - int flags = 0; + BdrvRequestFlags flags = 0; int c, cnt, ret; char *buf = NULL; int64_t offset; @@ -1229,7 +1230,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) { struct timespec t1, t2; bool Cflag = false, qflag = false; - int flags = 0; + BdrvRequestFlags flags = 0; int c, cnt, ret; char *buf; int64_t offset; @@ -1544,7 +1545,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) int nr_iov, c; int pattern = 0xcd; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - int flags = 0; + BdrvRequestFlags flags = 0; ctx->blk = blk; while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) { From 00e2a04c274cacfc2134e7b88f120ebe762f7223 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 7 Feb 2023 15:37:18 -0500 Subject: [PATCH 662/814] qemu-io: add -r option to register I/O buffer The blk_register_buf() API is an optimization hint that allows some block drivers to avoid I/O buffer housekeeping or bounce buffers. Add an -r option to register the I/O buffer so that qemu-io can be used to test the blk_register_buf() API. The next commit will add a test that uses the new option. Reviewed-by: Eric Blake Reviewed-by: Hanna Czenczek Signed-off-by: Stefan Hajnoczi Message-Id: <20230207203719.242926-4-stefanha@redhat.com> --- qemu-io-cmds.c | 206 +++++++++++++++++++++++++++++++------------------ 1 file changed, 130 insertions(+), 76 deletions(-) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 1f60c23ba4..e7a02f5b99 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -338,7 +338,8 @@ static int parse_pattern(const char *arg) */ #define MISALIGN_OFFSET 16 -static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern) +static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern, + bool register_buf) { void *buf; @@ -347,16 +348,24 @@ static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern) } buf = blk_blockalign(blk, len); memset(buf, pattern, len); + if (register_buf) { + blk_register_buf(blk, buf, len, &error_abort); + } if (qemuio_misalign) { buf += MISALIGN_OFFSET; } return buf; } -static void qemu_io_free(void *p) +static void qemu_io_free(BlockBackend *blk, void *p, size_t len, + bool unregister_buf) { if (qemuio_misalign) { p -= MISALIGN_OFFSET; + len += MISALIGN_OFFSET; + } + if (unregister_buf) { + blk_unregister_buf(blk, p, len); } qemu_vfree(p); } @@ -371,14 +380,16 @@ static void qemu_io_free(void *p) * @blk - the block backend where the buffer content is going to be written to * @len - the buffer length * @file_name - the file to read the content from + * @register_buf - call blk_register_buf() * * Returns: the buffer pointer on success * NULL on error */ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, - const char *file_name) + const char *file_name, bool register_buf) { - char *buf, *buf_origin; + size_t alloc_len = len + (qemuio_misalign ? MISALIGN_OFFSET : 0); + char *alloc_buf, *buf, *end; FILE *f = fopen(file_name, "r"); int pattern_len; @@ -387,19 +398,13 @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, return NULL; } - if (qemuio_misalign) { - len += MISALIGN_OFFSET; - } - - buf_origin = buf = blk_blockalign(blk, len); + alloc_buf = buf = blk_blockalign(blk, alloc_len); if (qemuio_misalign) { - buf_origin += MISALIGN_OFFSET; buf += MISALIGN_OFFSET; - len -= MISALIGN_OFFSET; } - pattern_len = fread(buf_origin, 1, len, f); + pattern_len = fread(buf, 1, len, f); if (ferror(f)) { perror(file_name); @@ -414,24 +419,23 @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, fclose(f); f = NULL; - if (len > pattern_len) { - len -= pattern_len; - buf += pattern_len; - - while (len > 0) { - size_t len_to_copy = MIN(pattern_len, len); - - memcpy(buf, buf_origin, len_to_copy); - - len -= len_to_copy; - buf += len_to_copy; - } + if (register_buf) { + blk_register_buf(blk, alloc_buf, alloc_len, &error_abort); } - return buf_origin; + end = buf + len; + for (char *p = buf + pattern_len; p < end; p += pattern_len) { + memcpy(p, buf, MIN(pattern_len, end - p)); + } + + return buf; error: - qemu_io_free(buf_origin); + /* + * This code path is only taken before blk_register_buf() is called, so + * hardcode the qemu_io_free() unregister_buf argument to false. + */ + qemu_io_free(blk, alloc_buf, alloc_len, false); if (f) { fclose(f); } @@ -490,7 +494,7 @@ static void print_report(const char *op, struct timespec *t, int64_t offset, */ static void * create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, - int pattern) + int pattern, bool register_buf) { size_t *sizes = g_new0(size_t, nr_iov); size_t count = 0; @@ -526,7 +530,7 @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov, qemu_iovec_init(qiov, nr_iov); - buf = p = qemu_io_alloc(blk, count, pattern); + buf = p = qemu_io_alloc(blk, count, pattern, register_buf); for (i = 0; i < nr_iov; i++) { qemu_iovec_add(qiov, p, sizes[i]); @@ -539,7 +543,7 @@ fail: } static int do_pread(BlockBackend *blk, char *buf, int64_t offset, - int64_t bytes, int64_t *total) + int64_t bytes, BdrvRequestFlags flags, int64_t *total) { int ret; @@ -547,7 +551,7 @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset, return -ERANGE; } - ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, 0); + ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, flags); if (ret < 0) { return ret; } @@ -638,11 +642,11 @@ static void aio_rw_done(void *opaque, int ret) } static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov, - int64_t offset, int *total) + int64_t offset, BdrvRequestFlags flags, int *total) { int async_ret = NOT_DONE; - blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret); + blk_aio_preadv(blk, offset, qiov, flags, aio_rw_done, &async_ret); while (async_ret == NOT_DONE) { main_loop_wait(false); } @@ -682,6 +686,7 @@ static void read_help(void) " -p, -- ignored for backwards compatibility\n" " -P, -- use a pattern to verify read data\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" " -s, -- start offset for pattern verification (only with -P)\n" " -v, -- dump buffer to standard output\n" "\n"); @@ -695,7 +700,7 @@ static const cmdinfo_t read_cmd = { .cfunc = read_f, .argmin = 2, .argmax = -1, - .args = "[-abCqv] [-P pattern [-s off] [-l len]] off len", + .args = "[-abCqrv] [-P pattern [-s off] [-l len]] off len", .oneline = "reads a number of bytes at a specified offset", .help = read_help, }; @@ -713,8 +718,9 @@ static int read_f(BlockBackend *blk, int argc, char **argv) int64_t total = 0; int pattern = 0; int64_t pattern_offset = 0, pattern_count = 0; + BdrvRequestFlags flags = 0; - while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) { + while ((c = getopt(argc, argv, "bCl:pP:qrs:v")) != -1) { switch (c) { case 'b': bflag = true; @@ -743,6 +749,9 @@ static int read_f(BlockBackend *blk, int argc, char **argv) case 'q': qflag = true; break; + case 'r': + flags |= BDRV_REQ_REGISTERED_BUF; + break; case 's': sflag = true; pattern_offset = cvtnum(optarg); @@ -807,15 +816,20 @@ static int read_f(BlockBackend *blk, int argc, char **argv) count); return -EINVAL; } + if (flags & BDRV_REQ_REGISTERED_BUF) { + printf("I/O buffer registration is not supported when reading " + "from vmstate\n"); + return -EINVAL; + } } - buf = qemu_io_alloc(blk, count, 0xab); + buf = qemu_io_alloc(blk, count, 0xab, flags & BDRV_REQ_REGISTERED_BUF); clock_gettime(CLOCK_MONOTONIC, &t1); if (bflag) { ret = do_load_vmstate(blk, buf, offset, count, &total); } else { - ret = do_pread(blk, buf, offset, count, &total); + ret = do_pread(blk, buf, offset, count, flags, &total); } clock_gettime(CLOCK_MONOTONIC, &t2); @@ -852,7 +866,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv) print_report("read", &t2, offset, count, total, cnt, Cflag); out: - qemu_io_free(buf); + qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF); return ret; } @@ -870,8 +884,9 @@ static void readv_help(void) " Uses multiple iovec buffers if more than one byte range is specified.\n" " -C, -- report statistics in a machine parsable format\n" " -P, -- use a pattern to verify read data\n" -" -v, -- dump buffer to standard output\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" +" -v, -- dump buffer to standard output\n" "\n"); } @@ -882,7 +897,7 @@ static const cmdinfo_t readv_cmd = { .cfunc = readv_f, .argmin = 2, .argmax = -1, - .args = "[-Cqv] [-P pattern] off len [len..]", + .args = "[-Cqrv] [-P pattern] off len [len..]", .oneline = "reads a number of bytes at a specified offset", .help = readv_help, }; @@ -900,8 +915,9 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) QEMUIOVector qiov; int pattern = 0; bool Pflag = false; + BdrvRequestFlags flags = 0; - while ((c = getopt(argc, argv, "CP:qv")) != -1) { + while ((c = getopt(argc, argv, "CP:qrv")) != -1) { switch (c) { case 'C': Cflag = true; @@ -916,6 +932,9 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) case 'q': qflag = true; break; + case 'r': + flags |= BDRV_REQ_REGISTERED_BUF; + break; case 'v': vflag = true; break; @@ -939,13 +958,14 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) optind++; nr_iov = argc - optind; - buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab, + flags & BDRV_REQ_REGISTERED_BUF); if (buf == NULL) { return -EINVAL; } clock_gettime(CLOCK_MONOTONIC, &t1); - ret = do_aio_readv(blk, &qiov, offset, &total); + ret = do_aio_readv(blk, &qiov, offset, flags, &total); clock_gettime(CLOCK_MONOTONIC, &t2); if (ret < 0) { @@ -980,8 +1000,8 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); out: + qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF); qemu_iovec_destroy(&qiov); - qemu_io_free(buf); return ret; } @@ -998,13 +1018,14 @@ static void write_help(void) " filled with a set pattern (0xcdcdcdcd).\n" " -b, -- write to the VM state rather than the virtual disk\n" " -c, -- write compressed data with blk_write_compressed\n" +" -C, -- report statistics in a machine parsable format\n" " -f, -- use Force Unit Access semantics\n" " -n, -- with -z, don't allow slow fallback\n" " -p, -- ignored for backwards compatibility\n" " -P, -- use different pattern to fill file\n" -" -s, -- use a pattern file to fill the write buffer\n" -" -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" +" -s, -- use a pattern file to fill the write buffer\n" " -u, -- with -z, allow unmapping\n" " -z, -- write zeroes using blk_pwrite_zeroes\n" "\n"); @@ -1019,7 +1040,7 @@ static const cmdinfo_t write_cmd = { .perm = BLK_PERM_WRITE, .argmin = 2, .argmax = -1, - .args = "[-bcCfnquz] [-P pattern | -s source_file] off len", + .args = "[-bcCfnqruz] [-P pattern | -s source_file] off len", .oneline = "writes a number of bytes at a specified offset", .help = write_help, }; @@ -1039,7 +1060,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) int pattern = 0xcd; const char *file_name = NULL; - while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) { + while ((c = getopt(argc, argv, "bcCfnpP:qrs:uz")) != -1) { switch (c) { case 'b': bflag = true; @@ -1069,6 +1090,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv) case 'q': qflag = true; break; + case 'r': + flags |= BDRV_REQ_REGISTERED_BUF; + break; case 's': sflag = true; file_name = optarg; @@ -1148,14 +1172,21 @@ static int write_f(BlockBackend *blk, int argc, char **argv) } } - if (!zflag) { + if (zflag) { + if (flags & BDRV_REQ_REGISTERED_BUF) { + printf("cannot combine zero write with registered I/O buffer\n"); + return -EINVAL; + } + } else { if (sflag) { - buf = qemu_io_alloc_from_file(blk, count, file_name); + buf = qemu_io_alloc_from_file(blk, count, file_name, + flags & BDRV_REQ_REGISTERED_BUF); if (!buf) { return -EINVAL; } } else { - buf = qemu_io_alloc(blk, count, pattern); + buf = qemu_io_alloc(blk, count, pattern, + flags & BDRV_REQ_REGISTERED_BUF); } } @@ -1189,7 +1220,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) out: if (!zflag) { - qemu_io_free(buf); + qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF); } return ret; } @@ -1206,10 +1237,11 @@ writev_help(void) "\n" " Writes into a segment of the currently open file, using a buffer\n" " filled with a set pattern (0xcdcdcdcd).\n" -" -P, -- use different pattern to fill file\n" " -C, -- report statistics in a machine parsable format\n" " -f, -- use Force Unit Access semantics\n" +" -P, -- use different pattern to fill file\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" "\n"); } @@ -1221,7 +1253,7 @@ static const cmdinfo_t writev_cmd = { .perm = BLK_PERM_WRITE, .argmin = 2, .argmax = -1, - .args = "[-Cfq] [-P pattern] off len [len..]", + .args = "[-Cfqr] [-P pattern] off len [len..]", .oneline = "writes a number of bytes at a specified offset", .help = writev_help, }; @@ -1240,7 +1272,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) int pattern = 0xcd; QEMUIOVector qiov; - while ((c = getopt(argc, argv, "CfqP:")) != -1) { + while ((c = getopt(argc, argv, "CfP:qr")) != -1) { switch (c) { case 'C': Cflag = true; @@ -1251,6 +1283,9 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) case 'q': qflag = true; break; + case 'r': + flags |= BDRV_REQ_REGISTERED_BUF; + break; case 'P': pattern = parse_pattern(optarg); if (pattern < 0) { @@ -1276,7 +1311,8 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) optind++; nr_iov = argc - optind; - buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern, + flags & BDRV_REQ_REGISTERED_BUF); if (buf == NULL) { return -EINVAL; } @@ -1301,8 +1337,8 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) t2 = tsub(t2, t1); print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); out: + qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF); qemu_iovec_destroy(&qiov); - qemu_io_free(buf); return ret; } @@ -1318,6 +1354,7 @@ struct aio_ctx { bool zflag; BlockAcctCookie acct; int pattern; + BdrvRequestFlags flags; struct timespec t1; }; @@ -1347,7 +1384,8 @@ static void aio_write_done(void *opaque, int ret) ctx->qiov.size, 1, ctx->Cflag); out: if (!ctx->zflag) { - qemu_io_free(ctx->buf); + qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size, + ctx->flags & BDRV_REQ_REGISTERED_BUF); qemu_iovec_destroy(&ctx->qiov); } g_free(ctx); @@ -1392,7 +1430,8 @@ static void aio_read_done(void *opaque, int ret) print_report("read", &t2, ctx->offset, ctx->qiov.size, ctx->qiov.size, 1, ctx->Cflag); out: - qemu_io_free(ctx->buf); + qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size, + ctx->flags & BDRV_REQ_REGISTERED_BUF); qemu_iovec_destroy(&ctx->qiov); g_free(ctx); } @@ -1414,10 +1453,11 @@ static void aio_read_help(void) " considered successful once the request is submitted, independently\n" " of potential I/O errors or pattern mismatches.\n" " -C, -- report statistics in a machine parsable format\n" -" -P, -- use a pattern to verify read data\n" " -i, -- treat request as invalid, for exercising stats\n" -" -v, -- dump buffer to standard output\n" +" -P, -- use a pattern to verify read data\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" +" -v, -- dump buffer to standard output\n" "\n"); } @@ -1428,7 +1468,7 @@ static const cmdinfo_t aio_read_cmd = { .cfunc = aio_read_f, .argmin = 2, .argmax = -1, - .args = "[-Ciqv] [-P pattern] off len [len..]", + .args = "[-Ciqrv] [-P pattern] off len [len..]", .oneline = "asynchronously reads a number of bytes", .help = aio_read_help, }; @@ -1439,7 +1479,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); ctx->blk = blk; - while ((c = getopt(argc, argv, "CP:iqv")) != -1) { + while ((c = getopt(argc, argv, "CiP:qrv")) != -1) { switch (c) { case 'C': ctx->Cflag = true; @@ -1460,6 +1500,9 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) case 'q': ctx->qflag = true; break; + case 'r': + ctx->flags |= BDRV_REQ_REGISTERED_BUF; + break; case 'v': ctx->vflag = true; break; @@ -1486,7 +1529,8 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) optind++; nr_iov = argc - optind; - ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab); + ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab, + ctx->flags & BDRV_REQ_REGISTERED_BUF); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); g_free(ctx); @@ -1496,7 +1540,8 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) clock_gettime(CLOCK_MONOTONIC, &ctx->t1); block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, BLOCK_ACCT_READ); - blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx); + blk_aio_preadv(blk, ctx->offset, &ctx->qiov, ctx->flags, aio_read_done, + ctx); return 0; } @@ -1517,11 +1562,12 @@ static void aio_write_help(void) " Note that due to its asynchronous nature, this command will be\n" " considered successful once the request is submitted, independently\n" " of potential I/O errors or pattern mismatches.\n" -" -P, -- use different pattern to fill file\n" " -C, -- report statistics in a machine parsable format\n" " -f, -- use Force Unit Access semantics\n" " -i, -- treat request as invalid, for exercising stats\n" +" -P, -- use different pattern to fill file\n" " -q, -- quiet mode, do not show I/O statistics\n" +" -r, -- register I/O buffer\n" " -u, -- with -z, allow unmapping\n" " -z, -- write zeroes using blk_aio_pwrite_zeroes\n" "\n"); @@ -1535,7 +1581,7 @@ static const cmdinfo_t aio_write_cmd = { .perm = BLK_PERM_WRITE, .argmin = 2, .argmax = -1, - .args = "[-Cfiquz] [-P pattern] off len [len..]", + .args = "[-Cfiqruz] [-P pattern] off len [len..]", .oneline = "asynchronously writes a number of bytes", .help = aio_write_help, }; @@ -1545,22 +1591,24 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) int nr_iov, c; int pattern = 0xcd; struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - BdrvRequestFlags flags = 0; ctx->blk = blk; - while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) { + while ((c = getopt(argc, argv, "CfiP:qruz")) != -1) { switch (c) { case 'C': ctx->Cflag = true; break; case 'f': - flags |= BDRV_REQ_FUA; + ctx->flags |= BDRV_REQ_FUA; break; case 'q': ctx->qflag = true; break; + case 'r': + ctx->flags |= BDRV_REQ_REGISTERED_BUF; + break; case 'u': - flags |= BDRV_REQ_MAY_UNMAP; + ctx->flags |= BDRV_REQ_MAY_UNMAP; break; case 'P': pattern = parse_pattern(optarg); @@ -1596,7 +1644,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } - if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { + if ((ctx->flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { printf("-u requires -z to be specified\n"); g_free(ctx); return -EINVAL; @@ -1608,6 +1656,12 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) return -EINVAL; } + if (ctx->zflag && (ctx->flags & BDRV_REQ_REGISTERED_BUF)) { + printf("cannot combine zero write with registered I/O buffer\n"); + g_free(ctx); + return -EINVAL; + } + ctx->offset = cvtnum(argv[optind]); if (ctx->offset < 0) { int ret = ctx->offset; @@ -1626,12 +1680,12 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) } ctx->qiov.size = count; - blk_aio_pwrite_zeroes(blk, ctx->offset, count, flags, aio_write_done, - ctx); + blk_aio_pwrite_zeroes(blk, ctx->offset, count, ctx->flags, + aio_write_done, ctx); } else { nr_iov = argc - optind; ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, - pattern); + pattern, ctx->flags & BDRV_REQ_REGISTERED_BUF); if (ctx->buf == NULL) { block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); g_free(ctx); @@ -1642,8 +1696,8 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, BLOCK_ACCT_WRITE); - blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done, - ctx); + blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, ctx->flags, + aio_write_done, ctx); } return 0; From acbc8aee5b09222dc6a5cb88306b67bcbe37e30b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 7 Feb 2023 15:37:19 -0500 Subject: [PATCH 663/814] iotests/detect-zeroes-registered-buf: add new test This regression test demonstrates that detect-zeroes works with registered buffers. Bug details: https://gitlab.com/qemu-project/qemu/-/issues/1404 Reviewed-by: Eric Blake Reviewed-by: Hanna Czenczek Signed-off-by: Stefan Hajnoczi Message-Id: <20230207203719.242926-5-stefanha@redhat.com> --- .../tests/detect-zeroes-registered-buf | 58 +++++++++++++++++++ .../tests/detect-zeroes-registered-buf.out | 7 +++ 2 files changed, 65 insertions(+) create mode 100755 tests/qemu-iotests/tests/detect-zeroes-registered-buf create mode 100644 tests/qemu-iotests/tests/detect-zeroes-registered-buf.out diff --git a/tests/qemu-iotests/tests/detect-zeroes-registered-buf b/tests/qemu-iotests/tests/detect-zeroes-registered-buf new file mode 100755 index 0000000000..edb5f2cee5 --- /dev/null +++ b/tests/qemu-iotests/tests/detect-zeroes-registered-buf @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# group: rw auto quick +# +# Check that detect-zeroes=unmap works on writes with registered I/O buffers. +# This is a regression test for +# https://gitlab.com/qemu-project/qemu/-/issues/1404 where I/O requests failed +# unexpectedly. +# +# Copyright Red Hat +# +# 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=stefanha@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +cd .. +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto generic + +size=128M +_make_test_img $size +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,discard=unmap,detect-zeroes=unmap" + +echo +echo "== writing zero buffer to image ==" +QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS_NO_FMT" $QEMU_IO -c "write -r -P 0 0 4k" --image-opts "$IMGSPEC" | _filter_qemu_io + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out b/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out new file mode 100644 index 0000000000..42c56fcc8d --- /dev/null +++ b/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out @@ -0,0 +1,7 @@ +QA output created by detect-zeroes-registered-buf +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 + +== writing zero buffer to image == +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done From 808d15b383fecb3ec540186f68767a211c756c5a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 6 Feb 2023 13:32:32 +0100 Subject: [PATCH 664/814] build: make meson-buildoptions.sh stable The library directory can change depending on the multilib setup of the host. It would be even better to detect it in configure with the same algorithm that Meson uses, but the important thing to avoid confusing developers is to have identical contents of scripts/meson-buildoptions.sh, independent of the distro and architecture on which it was created. So, for now just give a custom default value to libdir. Signed-off-by: Paolo Bonzini --- scripts/meson-buildoptions.py | 7 +++++-- scripts/meson-buildoptions.sh | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 3e2b478538..a04dcc70a5 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -61,7 +61,10 @@ LINE_WIDTH = 76 # Convert the default value of an option to the string used in # the help message -def value_to_help(value): +def get_help(opt): + if opt["name"] == "libdir": + return 'system default' + value = opt["value"] if isinstance(value, list): return ",".join(value) if isinstance(value, bool): @@ -88,7 +91,7 @@ def sh_print(line=""): def help_line(left, opt, indent, long): right = f'{opt["description"]}' if long: - value = value_to_help(opt["value"]) + value = get_help(opt) if value != "auto" and value != "": right += f" [{value}]" if "choices" in opt and long: diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 0f71e92dcb..d663c9cadf 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -49,7 +49,7 @@ meson_options_help() { printf "%s\n" ' --includedir=VALUE Header file directory [include]' printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' printf "%s\n" ' cpu name [/usr/gnemul/qemu-%M]' - printf "%s\n" ' --libdir=VALUE Library directory [lib64]' + printf "%s\n" ' --libdir=VALUE Library directory [system default]' printf "%s\n" ' --libexecdir=VALUE Library executable directory [libexec]' printf "%s\n" ' --localedir=VALUE Locale data directory [share/locale]' printf "%s\n" ' --localstatedir=VALUE Localstate data directory [/var/local]' From d76aa73fad1f64c192856e1420ad0756f5e3b778 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jan 2023 09:19:31 +0100 Subject: [PATCH 665/814] remove unnecessary extern "C" blocks A handful of header files in QEMU are wrapped with extern "C" blocks. These are not necessary: there are C++ source files anymore in QEMU, and even where there were some, they did not include most of these files anyway. Remove them for consistency. Signed-off-by: Paolo Bonzini --- include/disas/dis-asm.h | 8 -------- include/qemu/bswap.h | 8 -------- include/qemu/envlist.h | 8 -------- include/qemu/rcu.h | 8 -------- include/qemu/rcu_queue.h | 8 -------- include/qemu/uri.h | 7 ------- 6 files changed, 47 deletions(-) diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 64247ecb11..32cda9ef14 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -11,10 +11,6 @@ #include "qemu/bswap.h" -#ifdef __cplusplus -extern "C" { -#endif - typedef void *PTR; typedef uint64_t bfd_vma; typedef int64_t bfd_signed_vma; @@ -506,8 +502,4 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr) typedef bool bfd_boolean; -#ifdef __cplusplus -} -#endif - #endif /* DISAS_DIS_ASM_H */ diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 3cbe52246b..b1650daedf 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,10 +1,6 @@ #ifndef BSWAP_H #define BSWAP_H -#ifdef __cplusplus -extern "C" { -#endif - #undef bswap16 #define bswap16(_x) __builtin_bswap16(_x) #undef bswap32 @@ -395,8 +391,4 @@ DO_STN_LDN_P(be) #undef le_bswaps #undef be_bswaps -#ifdef __cplusplus -} -#endif - #endif /* BSWAP_H */ diff --git a/include/qemu/envlist.h b/include/qemu/envlist.h index b9addcc11f..6006dfae44 100644 --- a/include/qemu/envlist.h +++ b/include/qemu/envlist.h @@ -1,10 +1,6 @@ #ifndef ENVLIST_H #define ENVLIST_H -#ifdef __cplusplus -extern "C" { -#endif - typedef struct envlist envlist_t; envlist_t *envlist_create(void); @@ -15,8 +11,4 @@ int envlist_parse_set(envlist_t *, const char *); int envlist_parse_unset(envlist_t *, const char *); char **envlist_to_environ(const envlist_t *, size_t *); -#ifdef __cplusplus -} -#endif - #endif /* ENVLIST_H */ diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index b063c6fde8..313fc414bc 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -31,10 +31,6 @@ #include "qemu/sys_membarrier.h" #include "qemu/coroutine-tls.h" -#ifdef __cplusplus -extern "C" { -#endif - /* * Important ! * @@ -196,8 +192,4 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock) void rcu_add_force_rcu_notifier(Notifier *n); void rcu_remove_force_rcu_notifier(Notifier *n); -#ifdef __cplusplus -} -#endif - #endif /* QEMU_RCU_H */ diff --git a/include/qemu/rcu_queue.h b/include/qemu/rcu_queue.h index 0e53ddd530..4e6298d473 100644 --- a/include/qemu/rcu_queue.h +++ b/include/qemu/rcu_queue.h @@ -28,11 +28,6 @@ #include "qemu/queue.h" #include "qemu/atomic.h" -#ifdef __cplusplus -extern "C" { -#endif - - /* * List access methods. */ @@ -311,7 +306,4 @@ extern "C" { (var) && ((next) = qatomic_rcu_read(&(var)->field.sle_next), 1); \ (var) = (next)) -#ifdef __cplusplus -} -#endif #endif /* QEMU_RCU_QUEUE_H */ diff --git a/include/qemu/uri.h b/include/qemu/uri.h index d201c61260..db5218c39e 100644 --- a/include/qemu/uri.h +++ b/include/qemu/uri.h @@ -53,10 +53,6 @@ #ifndef QEMU_URI_H #define QEMU_URI_H -#ifdef __cplusplus -extern "C" { -#endif - /** * URI: * @@ -105,7 +101,4 @@ struct QueryParams *query_params_new (int init_alloc); extern QueryParams *query_params_parse (const char *query); extern void query_params_free (QueryParams *ps); -#ifdef __cplusplus -} -#endif #endif /* QEMU_URI_H */ From 5080152e2ef6cde7aa692e29880c62bd54acb750 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jan 2023 17:36:33 +0100 Subject: [PATCH 666/814] block/iscsi: fix double-free on BUSY or similar statuses Commit 8c460269aa77 ("iscsi: base all handling of check condition on scsi_sense_to_errno", 2019-07-15) removed a "goto out" so that the same coroutine is re-entered twice; once from iscsi_co_generic_cb, once from the timer callback iscsi_retry_timer_expired. This can cause a crash. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1378 Reported-by: Grzegorz Zdanowski Signed-off-by: Paolo Bonzini --- block/iscsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/iscsi.c b/block/iscsi.c index b3e10f40b6..3aacd0709f 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -269,6 +269,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, timer_mod(&iTask->retry_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); iTask->do_retry = 1; + return; } else if (status == SCSI_STATUS_CHECK_CONDITION) { int error = iscsi_translate_sense(&task->sense); if (error == EAGAIN) { From 78901b5047a2c27858f6c3e780ab3f2af5463631 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Jan 2023 11:35:40 +0100 Subject: [PATCH 667/814] vl: catch [accel] entry without accelerator Avoid a SIGSEGV and return an error instead. Reported-by: Thomas Huth Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1439 Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index b2ee3fee3f..459588aa7d 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2204,14 +2204,18 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp) int ret; bool qtest_with_kvm; + if (!acc) { + error_setg(errp, QERR_MISSING_PARAMETER, "accel"); + goto bad; + } + qtest_with_kvm = g_str_equal(acc, "kvm") && qtest_chrdev != NULL; if (!ac) { - *p_init_failed = true; if (!qtest_with_kvm) { error_report("invalid accelerator %s", acc); } - return 0; + goto bad; } accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac))); object_apply_compat_props(OBJECT(accel)); @@ -2221,14 +2225,17 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp) ret = accel_init_machine(accel, current_machine); if (ret < 0) { - *p_init_failed = true; if (!qtest_with_kvm || ret != -ENOENT) { error_report("failed to initialize %s: %s", acc, strerror(-ret)); } - return 0; + goto bad; } return 1; + +bad: + *p_init_failed = true; + return 0; } static void configure_accelerators(const char *progname) From 5d62d6649cd367b5b4a3676e7514d2f9ca86cb03 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 14 Jan 2023 13:05:41 -1000 Subject: [PATCH 668/814] tests/tcg/i386: Introduce and use reg_t consistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define reg_t based on the actual register width. Define the inlines using that type. This will allow input registers to 32-bit insns to be set to 64-bit values on x86-64, which allows testing various edge cases. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230114230542.3116013-2-richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini --- tests/tcg/i386/test-i386-bmi2.c | 182 ++++++++++++++++---------------- 1 file changed, 93 insertions(+), 89 deletions(-) diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c index 5fadf47510..3c3ef85513 100644 --- a/tests/tcg/i386/test-i386-bmi2.c +++ b/tests/tcg/i386/test-i386-bmi2.c @@ -3,34 +3,40 @@ #include #include +#ifdef __x86_64 +typedef uint64_t reg_t; +#else +typedef uint32_t reg_t; +#endif + #define insn1q(name, arg0) \ -static inline uint64_t name##q(uint64_t arg0) \ +static inline reg_t name##q(reg_t arg0) \ { \ - uint64_t result64; \ + reg_t result64; \ asm volatile (#name "q %1, %0" : "=r"(result64) : "rm"(arg0)); \ return result64; \ } #define insn1l(name, arg0) \ -static inline uint32_t name##l(uint32_t arg0) \ +static inline reg_t name##l(reg_t arg0) \ { \ - uint32_t result32; \ + reg_t result32; \ asm volatile (#name "l %k1, %k0" : "=r"(result32) : "rm"(arg0)); \ return result32; \ } #define insn2q(name, arg0, c0, arg1, c1) \ -static inline uint64_t name##q(uint64_t arg0, uint64_t arg1) \ +static inline reg_t name##q(reg_t arg0, reg_t arg1) \ { \ - uint64_t result64; \ + reg_t result64; \ asm volatile (#name "q %2, %1, %0" : "=r"(result64) : c0(arg0), c1(arg1)); \ return result64; \ } #define insn2l(name, arg0, c0, arg1, c1) \ -static inline uint32_t name##l(uint32_t arg0, uint32_t arg1) \ +static inline reg_t name##l(reg_t arg0, reg_t arg1) \ { \ - uint32_t result32; \ + reg_t result32; \ asm volatile (#name "l %k2, %k1, %k0" : "=r"(result32) : c0(arg0), c1(arg1)); \ return result32; \ } @@ -65,130 +71,128 @@ insn1l(blsr, src) int main(int argc, char *argv[]) { uint64_t ehlo = 0x202020204f4c4845ull; uint64_t mask = 0xa080800302020001ull; - uint32_t result32; + reg_t result; #ifdef __x86_64 - uint64_t result64; - /* 64 bits */ - result64 = andnq(mask, ehlo); - assert(result64 == 0x002020204d4c4844); + result = andnq(mask, ehlo); + assert(result == 0x002020204d4c4844); - result64 = pextq(ehlo, mask); - assert(result64 == 133); + result = pextq(ehlo, mask); + assert(result == 133); - result64 = pdepq(result64, mask); - assert(result64 == (ehlo & mask)); + result = pdepq(result, mask); + assert(result == (ehlo & mask)); - result64 = pextq(-1ull, mask); - assert(result64 == 511); /* mask has 9 bits set */ + result = pextq(-1ull, mask); + assert(result == 511); /* mask has 9 bits set */ - result64 = pdepq(-1ull, mask); - assert(result64 == mask); + result = pdepq(-1ull, mask); + assert(result == mask); - result64 = bextrq(mask, 0x3f00); - assert(result64 == (mask & ~INT64_MIN)); + result = bextrq(mask, 0x3f00); + assert(result == (mask & ~INT64_MIN)); - result64 = bextrq(mask, 0x1038); - assert(result64 == 0xa0); + result = bextrq(mask, 0x1038); + assert(result == 0xa0); - result64 = bextrq(mask, 0x10f8); - assert(result64 == 0); + result = bextrq(mask, 0x10f8); + assert(result == 0); - result64 = blsiq(0x30); - assert(result64 == 0x10); + result = blsiq(0x30); + assert(result == 0x10); - result64 = blsiq(0x30ull << 32); - assert(result64 == 0x10ull << 32); + result = blsiq(0x30ull << 32); + assert(result == 0x10ull << 32); - result64 = blsmskq(0x30); - assert(result64 == 0x1f); + result = blsmskq(0x30); + assert(result == 0x1f); - result64 = blsrq(0x30); - assert(result64 == 0x20); + result = blsrq(0x30); + assert(result == 0x20); - result64 = blsrq(0x30ull << 32); - assert(result64 == 0x20ull << 32); + result = blsrq(0x30ull << 32); + assert(result == 0x20ull << 32); - result64 = bzhiq(mask, 0x3f); - assert(result64 == (mask & ~INT64_MIN)); + result = bzhiq(mask, 0x3f); + assert(result == (mask & ~INT64_MIN)); - result64 = bzhiq(mask, 0x1f); - assert(result64 == (mask & ~(-1 << 30))); + result = bzhiq(mask, 0x1f); + assert(result == (mask & ~(-1 << 30))); - result64 = rorxq(0x2132435465768798, 8); - assert(result64 == 0x9821324354657687); + result = rorxq(0x2132435465768798, 8); + assert(result == 0x9821324354657687); - result64 = sarxq(0xffeeddccbbaa9988, 8); - assert(result64 == 0xffffeeddccbbaa99); + result = sarxq(0xffeeddccbbaa9988, 8); + assert(result == 0xffffeeddccbbaa99); - result64 = sarxq(0x77eeddccbbaa9988, 8 | 64); - assert(result64 == 0x0077eeddccbbaa99); + result = sarxq(0x77eeddccbbaa9988, 8 | 64); + assert(result == 0x0077eeddccbbaa99); - result64 = shrxq(0xffeeddccbbaa9988, 8); - assert(result64 == 0x00ffeeddccbbaa99); + result = shrxq(0xffeeddccbbaa9988, 8); + assert(result == 0x00ffeeddccbbaa99); - result64 = shrxq(0x77eeddccbbaa9988, 8 | 192); - assert(result64 == 0x0077eeddccbbaa99); + result = shrxq(0x77eeddccbbaa9988, 8 | 192); + assert(result == 0x0077eeddccbbaa99); - result64 = shlxq(0xffeeddccbbaa9988, 8); - assert(result64 == 0xeeddccbbaa998800); + result = shlxq(0xffeeddccbbaa9988, 8); + assert(result == 0xeeddccbbaa998800); #endif /* 32 bits */ - result32 = andnl(mask, ehlo); - assert(result32 == 0x04d4c4844); + result = andnl(mask, ehlo); + assert(result == 0x04d4c4844); - result32 = pextl((uint32_t) ehlo, mask); - assert(result32 == 5); + result = pextl((uint32_t) ehlo, mask); + assert(result == 5); - result32 = pdepl(result32, mask); - assert(result32 == (uint32_t)(ehlo & mask)); + result = pdepl(result, mask); + assert(result == (uint32_t)(ehlo & mask)); - result32 = pextl(-1u, mask); - assert(result32 == 7); /* mask has 3 bits set */ + result = pextl(-1u, mask); + assert(result == 7); /* mask has 3 bits set */ - result32 = pdepl(-1u, mask); - assert(result32 == (uint32_t)mask); + result = pdepl(-1u, mask); + assert(result == (uint32_t)mask); - result32 = bextrl(mask, 0x1f00); - assert(result32 == (mask & ~INT32_MIN)); + result = bextrl(mask, 0x1f00); + assert(result == (mask & ~INT32_MIN)); - result32 = bextrl(ehlo, 0x1018); - assert(result32 == 0x4f); + result = bextrl(ehlo, 0x1018); + assert(result == 0x4f); - result32 = bextrl(mask, 0x1038); - assert(result32 == 0); + result = bextrl(mask, 0x1038); + assert(result == 0); - result32 = blsil(0xffff); - assert(result32 == 1); + result = blsil(0xffff); + assert(result == 1); - result32 = blsmskl(0x300); - assert(result32 == 0x1ff); + result = blsmskl(0x300); + assert(result == 0x1ff); - result32 = blsrl(0xffc); - assert(result32 == 0xff8); + result = blsrl(0xffc); + assert(result == 0xff8); - result32 = bzhil(mask, 0xf); - assert(result32 == 1); + result = bzhil(mask, 0xf); + assert(result == 1); - result32 = rorxl(0x65768798, 8); - assert(result32 == 0x98657687); + result = rorxl(0x65768798, 8); + assert(result == 0x98657687); - result32 = sarxl(0xffeeddcc, 8); - assert(result32 == 0xffffeedd); + result = sarxl(0xffeeddcc, 8); + assert(result == 0xffffeedd); - result32 = sarxl(0x77eeddcc, 8 | 32); - assert(result32 == 0x0077eedd); + result = sarxl(0x77eeddcc, 8 | 32); + assert(result == 0x0077eedd); - result32 = shrxl(0xffeeddcc, 8); - assert(result32 == 0x00ffeedd); + result = shrxl(0xffeeddcc, 8); + assert(result == 0x00ffeedd); - result32 = shrxl(0x77eeddcc, 8 | 128); - assert(result32 == 0x0077eedd); + result = shrxl(0x77eeddcc, 8 | 128); + assert(result == 0x0077eedd); - result32 = shlxl(0xffeeddcc, 8); - assert(result32 == 0xeeddcc00); + result = shlxl(0xffeeddcc, 8); + assert(result == 0xeeddcc00); return 0; } From b14c0098975264ed03144f145bca0179a6763a07 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 14 Jan 2023 13:05:42 -1000 Subject: [PATCH 669/814] target/i386: Fix BEXTR instruction There were two problems here: not limiting the input to operand bits, and not correctly handling large extraction length. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1372 Signed-off-by: Richard Henderson Message-Id: <20230114230542.3116013-3-richard.henderson@linaro.org> Cc: qemu-stable@nongnu.org Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 22 +++++++++++----------- tests/tcg/i386/test-i386-bmi2.c | 12 ++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 7037ff91c6..99f6ba6e19 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1078,30 +1078,30 @@ static void gen_ANDN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) static void gen_BEXTR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { MemOp ot = decode->op[0].ot; - TCGv bound, zero; + TCGv bound = tcg_constant_tl(ot == MO_64 ? 63 : 31); + TCGv zero = tcg_constant_tl(0); + TCGv mone = tcg_constant_tl(-1); /* * Extract START, and shift the operand. * Shifts larger than operand size get zeros. */ tcg_gen_ext8u_tl(s->A0, s->T1); + if (TARGET_LONG_BITS == 64 && ot == MO_32) { + tcg_gen_ext32u_tl(s->T0, s->T0); + } tcg_gen_shr_tl(s->T0, s->T0, s->A0); - bound = tcg_constant_tl(ot == MO_64 ? 63 : 31); - zero = tcg_constant_tl(0); tcg_gen_movcond_tl(TCG_COND_LEU, s->T0, s->A0, bound, s->T0, zero); /* - * Extract the LEN into a mask. Lengths larger than - * operand size get all ones. + * Extract the LEN into an inverse mask. Lengths larger than + * operand size get all zeros, length 0 gets all ones. */ tcg_gen_extract_tl(s->A0, s->T1, 8, 8); - tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->A0, bound, s->A0, bound); - - tcg_gen_movi_tl(s->T1, 1); - tcg_gen_shl_tl(s->T1, s->T1, s->A0); - tcg_gen_subi_tl(s->T1, s->T1, 1); - tcg_gen_and_tl(s->T0, s->T0, s->T1); + tcg_gen_shl_tl(s->T1, mone, s->A0); + tcg_gen_movcond_tl(TCG_COND_LEU, s->T1, s->A0, bound, s->T1, zero); + tcg_gen_andc_tl(s->T0, s->T0, s->T1); gen_op_update1_cc(s); set_cc_op(s, CC_OP_LOGICB + ot); diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c index 3c3ef85513..982d4abda4 100644 --- a/tests/tcg/i386/test-i386-bmi2.c +++ b/tests/tcg/i386/test-i386-bmi2.c @@ -99,6 +99,9 @@ int main(int argc, char *argv[]) { result = bextrq(mask, 0x10f8); assert(result == 0); + result = bextrq(0xfedcba9876543210ull, 0x7f00); + assert(result == 0xfedcba9876543210ull); + result = blsiq(0x30); assert(result == 0x10); @@ -164,6 +167,15 @@ int main(int argc, char *argv[]) { result = bextrl(mask, 0x1038); assert(result == 0); + result = bextrl((reg_t)0x8f635a775ad3b9b4ull, 0x3018); + assert(result == 0x5a); + + result = bextrl((reg_t)0xfedcba9876543210ull, 0x7f00); + assert(result == 0x76543210u); + + result = bextrl(-1, 0); + assert(result == 0); + result = blsil(0xffff); assert(result == 1); From 99282098dc74c2055bde5652bde6cf0067d0c370 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 14 Jan 2023 08:06:01 -1000 Subject: [PATCH 670/814] target/i386: Fix C flag for BLSI, BLSMSK, BLSR We forgot to set cc_src, which is used for computing C. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1370 Signed-off-by: Richard Henderson Message-Id: <20230114180601.2993644-1-richard.henderson@linaro.org> Cc: qemu-stable@nongnu.org Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 99f6ba6e19..4d7702c106 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1111,6 +1111,7 @@ static void gen_BLSI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { MemOp ot = decode->op[0].ot; + tcg_gen_mov_tl(cpu_cc_src, s->T0); tcg_gen_neg_tl(s->T1, s->T0); tcg_gen_and_tl(s->T0, s->T0, s->T1); tcg_gen_mov_tl(cpu_cc_dst, s->T0); @@ -1121,6 +1122,7 @@ static void gen_BLSMSK(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode { MemOp ot = decode->op[0].ot; + tcg_gen_mov_tl(cpu_cc_src, s->T0); tcg_gen_subi_tl(s->T1, s->T0, 1); tcg_gen_xor_tl(s->T0, s->T0, s->T1); tcg_gen_mov_tl(cpu_cc_dst, s->T0); @@ -1131,6 +1133,7 @@ static void gen_BLSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { MemOp ot = decode->op[0].ot; + tcg_gen_mov_tl(cpu_cc_src, s->T0); tcg_gen_subi_tl(s->T1, s->T0, 1); tcg_gen_and_tl(s->T0, s->T0, s->T1); tcg_gen_mov_tl(cpu_cc_dst, s->T0); From 60c7dd22e1383754d5f150bc9f7c2785c662a7b6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Jan 2023 09:48:03 +0100 Subject: [PATCH 671/814] target/i386: fix ADOX followed by ADCX When ADCX is followed by ADOX or vice versa, the second instruction's carry comes from EFLAGS and the condition codes use the CC_OP_ADCOX operation. Retrieving the carry from EFLAGS is handled by this bit of gen_ADCOX: tcg_gen_extract_tl(carry_in, cpu_cc_src, ctz32(cc_op == CC_OP_ADCX ? CC_C : CC_O), 1); Unfortunately, in this case cc_op has been overwritten by the previous "if" statement to CC_OP_ADCOX. This works by chance when the first instruction is ADCX; however, if the first instruction is ADOX, ADCX will incorrectly take its carry from OF instead of CF. Fix by moving the computation of the new cc_op at the end of the function. The included exhaustive test case fails without this patch and passes afterwards. Because ADCX/ADOX need not be invoked through the VEX prefix, this regression bisects to commit 16fc5726a6e2 ("target/i386: reimplement 0x0f 0x38, add AVX", 2022-10-18). However, the mistake happened a little earlier, when BMI instructions were rewritten using the new decoder framework. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1471 Reported-by: Paul Jolly Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 20 +++++---- tests/tcg/i386/Makefile.target | 6 ++- tests/tcg/i386/test-i386-adcox.c | 75 ++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 tests/tcg/i386/test-i386-adcox.c diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 4d7702c106..0d7c6e80ae 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1015,6 +1015,7 @@ VSIB_AVX(VPGATHERQ, vpgatherq) static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op) { + int opposite_cc_op; TCGv carry_in = NULL; TCGv carry_out = (cc_op == CC_OP_ADCX ? cpu_cc_dst : cpu_cc_src2); TCGv zero; @@ -1022,14 +1023,8 @@ static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op) if (cc_op == s->cc_op || s->cc_op == CC_OP_ADCOX) { /* Re-use the carry-out from a previous round. */ carry_in = carry_out; - cc_op = s->cc_op; - } else if (s->cc_op == CC_OP_ADCX || s->cc_op == CC_OP_ADOX) { - /* Merge with the carry-out from the opposite instruction. */ - cc_op = CC_OP_ADCOX; - } - - /* If we don't have a carry-in, get it out of EFLAGS. */ - if (!carry_in) { + } else { + /* We don't have a carry-in, get it out of EFLAGS. */ if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { gen_compute_eflags(s); } @@ -1053,7 +1048,14 @@ static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op) tcg_gen_add2_tl(s->T0, carry_out, s->T0, carry_out, s->T1, zero); break; } - set_cc_op(s, cc_op); + + opposite_cc_op = cc_op == CC_OP_ADCX ? CC_OP_ADOX : CC_OP_ADCX; + if (s->cc_op == CC_OP_ADCOX || s->cc_op == opposite_cc_op) { + /* Merge with the carry-out from the opposite instruction. */ + set_cc_op(s, CC_OP_ADCOX); + } else { + set_cc_op(s, cc_op); + } } static void gen_ADCX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 81831cafbc..bafd8c2180 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -14,7 +14,7 @@ config-cc.mak: Makefile I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c)) ALL_X86_TESTS=$(I386_SRCS:.c=) SKIP_I386_TESTS=test-i386-ssse3 test-avx test-3dnow test-mmx -X86_64_TESTS:=$(filter test-i386-bmi2 $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) +X86_64_TESTS:=$(filter test-i386-adcox test-i386-bmi2 $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max @@ -28,6 +28,10 @@ test-i386-bmi2: CFLAGS=-O2 run-test-i386-bmi2: QEMU_OPTS += -cpu max run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max +test-i386-adcox: CFLAGS=-O2 +run-test-i386-adcox: QEMU_OPTS += -cpu max +run-plugin-test-i386-adcox-%: QEMU_OPTS += -cpu max + # # hello-i386 is a barebones app # diff --git a/tests/tcg/i386/test-i386-adcox.c b/tests/tcg/i386/test-i386-adcox.c new file mode 100644 index 0000000000..16169efff8 --- /dev/null +++ b/tests/tcg/i386/test-i386-adcox.c @@ -0,0 +1,75 @@ +/* See if various BMI2 instructions give expected results */ +#include +#include +#include + +#define CC_C 1 +#define CC_O (1 << 11) + +#ifdef __x86_64__ +#define REG uint64_t +#else +#define REG uint32_t +#endif + +void test_adox_adcx(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_operand) +{ + REG flags; + REG out_adcx, out_adox; + + asm("pushf; pop %0" : "=r"(flags)); + flags &= ~(CC_C | CC_O); + flags |= (in_c ? CC_C : 0); + flags |= (in_o ? CC_O : 0); + + out_adcx = adcx_operand; + out_adox = adox_operand; + asm("push %0; popf;" + "adox %3, %2;" + "adcx %3, %1;" + "pushf; pop %0" + : "+r" (flags), "+r" (out_adcx), "+r" (out_adox) + : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox)); + + assert(out_adcx == in_c + adcx_operand - 1); + assert(out_adox == in_o + adox_operand - 1); + assert(!!(flags & CC_C) == (in_c || adcx_operand)); + assert(!!(flags & CC_O) == (in_o || adox_operand)); +} + +void test_adcx_adox(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_operand) +{ + REG flags; + REG out_adcx, out_adox; + + asm("pushf; pop %0" : "=r"(flags)); + flags &= ~(CC_C | CC_O); + flags |= (in_c ? CC_C : 0); + flags |= (in_o ? CC_O : 0); + + out_adcx = adcx_operand; + out_adox = adox_operand; + asm("push %0; popf;" + "adcx %3, %1;" + "adox %3, %2;" + "pushf; pop %0" + : "+r" (flags), "+r" (out_adcx), "+r" (out_adox) + : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox)); + + assert(out_adcx == in_c + adcx_operand - 1); + assert(out_adox == in_o + adox_operand - 1); + assert(!!(flags & CC_C) == (in_c || adcx_operand)); + assert(!!(flags & CC_O) == (in_o || adox_operand)); +} + +int main(int argc, char *argv[]) { + /* try all combinations of input CF, input OF, CF from op1+op2, OF from op2+op1 */ + int i; + for (i = 0; i <= 15; i++) { + printf("%d\n", i); + test_adcx_adox(!!(i & 1), !!(i & 2), !!(i & 4), !!(i & 8)); + test_adox_adcx(!!(i & 1), !!(i & 2), !!(i & 4), !!(i & 8)); + } + return 0; +} + From 786c5256d3262518d8805ac2a62eb1c4a3813b80 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Jan 2023 11:27:14 +0100 Subject: [PATCH 672/814] libqtest: split qtest_spawn_qemu function In order to create a function that allows testing of invalid command lines, extract the parts of qtest_init_without_qmp_handshake that do not require any successful set up of sockets. Signed-off-by: Paolo Bonzini --- tests/qtest/libqtest.c | 103 ++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index d658222a19..4e1f4fb91c 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -360,60 +360,25 @@ static pid_t qtest_create_process(char *cmd) } #endif /* _WIN32 */ -QTestState *qtest_init_without_qmp_handshake(const char *extra_args) +static QTestState *G_GNUC_PRINTF(1, 2) qtest_spawn_qemu(const char *fmt, ...) { - QTestState *s; - int sock, qmpsock, i; - gchar *socket_path; - gchar *qmp_socket_path; - gchar *command; - const char *qemu_binary = qtest_qemu_binary(); + va_list ap; + QTestState *s = g_new0(QTestState, 1); const char *trace = g_getenv("QTEST_TRACE"); g_autofree char *tracearg = trace ? g_strdup_printf("-trace %s ", trace) : g_strdup(""); + g_autoptr(GString) command = g_string_new(""); - s = g_new(QTestState, 1); - - socket_path = g_strdup_printf("%s/qtest-%d.sock", - g_get_tmp_dir(), getpid()); - qmp_socket_path = g_strdup_printf("%s/qtest-%d.qmp", - g_get_tmp_dir(), getpid()); - - /* It's possible that if an earlier test run crashed it might - * have left a stale unix socket lying around. Delete any - * stale old socket to avoid spurious test failures with - * tests/libqtest.c:70:init_socket: assertion failed (ret != -1): (-1 != -1) - */ - unlink(socket_path); - unlink(qmp_socket_path); - - socket_init(); - sock = init_socket(socket_path); - qmpsock = init_socket(qmp_socket_path); - - qtest_client_set_rx_handler(s, qtest_client_socket_recv_line); - qtest_client_set_tx_handler(s, qtest_client_socket_send); + va_start(ap, fmt); + g_string_append_printf(command, CMD_EXEC "%s %s", + qtest_qemu_binary(), tracearg); + g_string_append_vprintf(command, fmt, ap); + va_end(ap); qtest_add_abrt_handler(kill_qemu_hook_func, s); - command = g_strdup_printf(CMD_EXEC "%s %s" - "-qtest unix:%s " - "-qtest-log %s " - "-chardev socket,path=%s,id=char0 " - "-mon chardev=char0,mode=control " - "-display none " - "%s" - " -accel qtest", - qemu_binary, tracearg, socket_path, - getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL, - qmp_socket_path, - extra_args ?: ""); + g_test_message("starting QEMU: %s", command->str); - g_test_message("starting QEMU: %s", command); - - s->pending_events = NULL; - s->wstatus = 0; - s->expected_status = 0; #ifndef _WIN32 s->qemu_pid = fork(); if (s->qemu_pid == 0) { @@ -434,14 +399,56 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args) if (!g_setenv("QEMU_AUDIO_DRV", "none", true)) { exit(1); } - execlp("/bin/sh", "sh", "-c", command, NULL); + execlp("/bin/sh", "sh", "-c", command->str, NULL); exit(1); } #else - s->qemu_pid = qtest_create_process(command); + s->qemu_pid = qtest_create_process(command->str); #endif /* _WIN32 */ - g_free(command); + return s; +} + +QTestState *qtest_init_without_qmp_handshake(const char *extra_args) +{ + QTestState *s; + int sock, qmpsock, i; + gchar *socket_path; + gchar *qmp_socket_path; + + socket_path = g_strdup_printf("%s/qtest-%d.sock", + g_get_tmp_dir(), getpid()); + qmp_socket_path = g_strdup_printf("%s/qtest-%d.qmp", + g_get_tmp_dir(), getpid()); + + /* + * It's possible that if an earlier test run crashed it might + * have left a stale unix socket lying around. Delete any + * stale old socket to avoid spurious test failures with + * tests/libqtest.c:70:init_socket: assertion failed (ret != -1): (-1 != -1) + */ + unlink(socket_path); + unlink(qmp_socket_path); + + socket_init(); + sock = init_socket(socket_path); + qmpsock = init_socket(qmp_socket_path); + + s = qtest_spawn_qemu("-qtest unix:%s " + "-qtest-log %s " + "-chardev socket,path=%s,id=char0 " + "-mon chardev=char0,mode=control " + "-display none " + "%s" + " -accel qtest", + socket_path, + getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL, + qmp_socket_path, + extra_args ?: ""); + + qtest_client_set_rx_handler(s, qtest_client_socket_recv_line); + qtest_client_set_tx_handler(s, qtest_client_socket_send); + s->fd = socket_accept(sock); if (s->fd >= 0) { s->qmp_fd = socket_accept(qmpsock); From 12008ff748d8cfb62fb937559c0fd844371bab5e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Jan 2023 12:01:20 +0100 Subject: [PATCH 673/814] libqtest: ensure waitpid() is only called once If a test aborts after qtest_wait_qemu() is called, the SIGABRT hooks are still in place and waitpid() is called again. The second time it is called, the process does not exist anymore and the system call fails. Move the s->qemu_pid = -1 assignment to qtest_wait_qemu() to make it idempotent, and anyway remove the SIGABRT hook as well to avoid that qtest_check_status() is called twice. Because of the extra call, qtest_remove_abrt_handler() now has to be made idempotent as well. Signed-off-by: Paolo Bonzini --- tests/qtest/libqtest.c | 55 +++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 4e1f4fb91c..2bfd460531 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -158,6 +158,7 @@ bool qtest_probe_child(QTestState *s) CloseHandle((HANDLE)pid); #endif s->qemu_pid = -1; + qtest_remove_abrt_handler(s); } return false; } @@ -169,6 +170,8 @@ void qtest_set_expected_status(QTestState *s, int status) static void qtest_check_status(QTestState *s) { + assert(s->qemu_pid == -1); + /* * Check whether qemu exited with expected exit status; anything else is * fishy and should be logged with as much detail as possible. @@ -202,36 +205,40 @@ static void qtest_check_status(QTestState *s) void qtest_wait_qemu(QTestState *s) { + if (s->qemu_pid != -1) { #ifndef _WIN32 - pid_t pid; - uint64_t end; + pid_t pid; + uint64_t end; - /* poll for a while until sending SIGKILL */ - end = g_get_monotonic_time() + WAITPID_TIMEOUT * G_TIME_SPAN_SECOND; + /* poll for a while until sending SIGKILL */ + end = g_get_monotonic_time() + WAITPID_TIMEOUT * G_TIME_SPAN_SECOND; - do { - pid = waitpid(s->qemu_pid, &s->wstatus, WNOHANG); - if (pid != 0) { - break; + do { + pid = waitpid(s->qemu_pid, &s->wstatus, WNOHANG); + if (pid != 0) { + break; + } + g_usleep(100 * 1000); + } while (g_get_monotonic_time() < end); + + if (pid == 0) { + kill(s->qemu_pid, SIGKILL); + pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0)); } - g_usleep(100 * 1000); - } while (g_get_monotonic_time() < end); - if (pid == 0) { - kill(s->qemu_pid, SIGKILL); - pid = RETRY_ON_EINTR(waitpid(s->qemu_pid, &s->wstatus, 0)); - } - - assert(pid == s->qemu_pid); + assert(pid == s->qemu_pid); #else - DWORD ret; + DWORD ret; - ret = WaitForSingleObject((HANDLE)s->qemu_pid, INFINITE); - assert(ret == WAIT_OBJECT_0); - GetExitCodeProcess((HANDLE)s->qemu_pid, &s->exit_code); - CloseHandle((HANDLE)s->qemu_pid); + ret = WaitForSingleObject((HANDLE)s->qemu_pid, INFINITE); + assert(ret == WAIT_OBJECT_0); + GetExitCodeProcess((HANDLE)s->qemu_pid, &s->exit_code); + CloseHandle((HANDLE)s->qemu_pid); #endif + s->qemu_pid = -1; + qtest_remove_abrt_handler(s); + } qtest_check_status(s); } @@ -245,7 +252,6 @@ void qtest_kill_qemu(QTestState *s) TerminateProcess((HANDLE)s->qemu_pid, s->expected_status); #endif qtest_wait_qemu(s); - s->qemu_pid = -1; return; } @@ -307,6 +313,11 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data) void qtest_remove_abrt_handler(void *data) { GHook *hook = g_hook_find_data(&abrt_hooks, TRUE, data); + + if (!hook) { + return; + } + g_hook_destroy_link(&abrt_hooks, hook); /* Uninstall SIGABRT handler on last instance */ From b530ccde5dd6403d576845918f70703357871e12 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 8 Feb 2023 19:04:34 +0100 Subject: [PATCH 674/814] migration: Remove spurious files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I introduced spurious files on my tree during a rebase: commit ebfc57871506b3fe36cc41f69ee3ad31a34afd63 Author: Zhenzhong Duan Date: Mon Oct 17 15:53:51 2022 +0800 multifd: Fix flush of zero copy page send request Make IO channel flush call after the inflight request has been drained in multifd thread, or else we may missed to flush the inflight request. Signed-off-by: Zhenzhong Duan Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela To make things worse, it appears like Zhenzhong is the one to blame. for(int i=0; i < 1000000; i++) { printf("I will not do rebases when I am tired\n"); } Sorry, Juan. Reviewed-by: Cédric Le Goater Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Juan Quintela --- .../x86_64-quintela-devices.mak | 7 - .../x86_64-quintela2-devices.mak | 6 - migration/multifd.c.orig | 1274 ----------------- 3 files changed, 1287 deletions(-) delete mode 100644 configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak delete mode 100644 configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak delete mode 100644 migration/multifd.c.orig diff --git a/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak b/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak deleted file mode 100644 index ee2bb8c5c9..0000000000 --- a/configs/devices/x86_64-softmmu/x86_64-quintela-devices.mak +++ /dev/null @@ -1,7 +0,0 @@ -# Boards: -# -CONFIG_ISAPC=n -CONFIG_I440FX=n -CONFIG_Q35=n -CONFIG_MICROVM=y - diff --git a/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak b/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak deleted file mode 100644 index f7e4dae842..0000000000 --- a/configs/devices/x86_64-softmmu/x86_64-quintela2-devices.mak +++ /dev/null @@ -1,6 +0,0 @@ -# Boards: -# -CONFIG_ISAPC=y -CONFIG_I440FX=y -CONFIG_Q35=y -CONFIG_MICROVM=y diff --git a/migration/multifd.c.orig b/migration/multifd.c.orig deleted file mode 100644 index ad89293b4e..0000000000 --- a/migration/multifd.c.orig +++ /dev/null @@ -1,1274 +0,0 @@ -/* - * Multifd common code - * - * Copyright (c) 2019-2020 Red Hat Inc - * - * Authors: - * Juan Quintela - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu/rcu.h" -#include "exec/target_page.h" -#include "sysemu/sysemu.h" -#include "exec/ramblock.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "ram.h" -#include "migration.h" -#include "socket.h" -#include "tls.h" -#include "qemu-file.h" -#include "trace.h" -#include "multifd.h" - -#include "qemu/yank.h" -#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; - unsigned char uuid[16]; /* QemuUUID */ - uint8_t id; - uint8_t unused1[7]; /* Reserved for future use */ - uint64_t unused2[4]; /* Reserved for future use */ -} __attribute__((packed)) MultiFDInit_t; - -/* Multifd without compression */ - -/** - * nocomp_send_setup: setup send side - * - * For no compression this function does nothing. - * - * Returns 0 for success or -1 for error - * - * @p: Params for the channel that we are using - * @errp: pointer to an error - */ -static int nocomp_send_setup(MultiFDSendParams *p, Error **errp) -{ - return 0; -} - -/** - * nocomp_send_cleanup: cleanup send side - * - * For no compression this function does nothing. - * - * @p: Params for the channel that we are using - * @errp: pointer to an error - */ -static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) -{ - return; -} - -/** - * nocomp_send_prepare: prepare date to be able to send - * - * For no compression we just have to calculate the size of the - * packet. - * - * Returns 0 for success or -1 for error - * - * @p: Params for the channel that we are using - * @errp: pointer to an error - */ -static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) -{ - MultiFDPages_t *pages = p->pages; - - for (int i = 0; i < p->normal_num; i++) { - p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i]; - p->iov[p->iovs_num].iov_len = p->page_size; - p->iovs_num++; - } - - p->next_packet_size = p->normal_num * p->page_size; - p->flags |= MULTIFD_FLAG_NOCOMP; - return 0; -} - -/** - * nocomp_recv_setup: setup receive side - * - * For no compression this function does nothing. - * - * Returns 0 for success or -1 for error - * - * @p: Params for the channel that we are using - * @errp: pointer to an error - */ -static int nocomp_recv_setup(MultiFDRecvParams *p, Error **errp) -{ - return 0; -} - -/** - * nocomp_recv_cleanup: setup receive side - * - * For no compression this function does nothing. - * - * @p: Params for the channel that we are using - */ -static void nocomp_recv_cleanup(MultiFDRecvParams *p) -{ -} - -/** - * nocomp_recv_pages: read the data from the channel into actual pages - * - * For no compression we just need to read things into the correct place. - * - * Returns 0 for success or -1 for error - * - * @p: Params for the channel that we are using - * @errp: pointer to an error - */ -static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) -{ - uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; - - if (flags != MULTIFD_FLAG_NOCOMP) { - error_setg(errp, "multifd %u: flags received %x flags expected %x", - p->id, flags, MULTIFD_FLAG_NOCOMP); - return -1; - } - for (int i = 0; i < p->normal_num; i++) { - p->iov[i].iov_base = p->host + p->normal[i]; - p->iov[i].iov_len = p->page_size; - } - return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp); -} - -static MultiFDMethods multifd_nocomp_ops = { - .send_setup = nocomp_send_setup, - .send_cleanup = nocomp_send_cleanup, - .send_prepare = nocomp_send_prepare, - .recv_setup = nocomp_recv_setup, - .recv_cleanup = nocomp_recv_cleanup, - .recv_pages = nocomp_recv_pages -}; - -static MultiFDMethods *multifd_ops[MULTIFD_COMPRESSION__MAX] = { - [MULTIFD_COMPRESSION_NONE] = &multifd_nocomp_ops, -}; - -void multifd_register_ops(int method, MultiFDMethods *ops) -{ - assert(0 < method && method < MULTIFD_COMPRESSION__MAX); - multifd_ops[method] = ops; -} - -static int multifd_send_initial_packet(MultiFDSendParams *p, Error **errp) -{ - MultiFDInit_t msg = {}; - int ret; - - msg.magic = cpu_to_be32(MULTIFD_MAGIC); - msg.version = cpu_to_be32(MULTIFD_VERSION); - msg.id = p->id; - memcpy(msg.uuid, &qemu_uuid.data, sizeof(msg.uuid)); - - ret = qio_channel_write_all(p->c, (char *)&msg, sizeof(msg), errp); - if (ret != 0) { - return -1; - } - return 0; -} - -static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) -{ - MultiFDInit_t msg; - int ret; - - ret = qio_channel_read_all(c, (char *)&msg, sizeof(msg), errp); - if (ret != 0) { - return -1; - } - - msg.magic = be32_to_cpu(msg.magic); - msg.version = be32_to_cpu(msg.version); - - if (msg.magic != MULTIFD_MAGIC) { - error_setg(errp, "multifd: received packet magic %x " - "expected %x", msg.magic, MULTIFD_MAGIC); - return -1; - } - - if (msg.version != MULTIFD_VERSION) { - error_setg(errp, "multifd: received packet version %u " - "expected %u", msg.version, MULTIFD_VERSION); - return -1; - } - - if (memcmp(msg.uuid, &qemu_uuid, sizeof(qemu_uuid))) { - char *uuid = qemu_uuid_unparse_strdup(&qemu_uuid); - char *msg_uuid = qemu_uuid_unparse_strdup((const QemuUUID *)msg.uuid); - - error_setg(errp, "multifd: received uuid '%s' and expected " - "uuid '%s' for channel %hhd", msg_uuid, uuid, msg.id); - g_free(uuid); - g_free(msg_uuid); - return -1; - } - - if (msg.id > migrate_multifd_channels()) { - error_setg(errp, "multifd: received channel version %u " - "expected %u", msg.version, MULTIFD_VERSION); - return -1; - } - - return msg.id; -} - -static MultiFDPages_t *multifd_pages_init(size_t size) -{ - MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1); - - pages->allocated = size; - pages->offset = g_new0(ram_addr_t, size); - - return pages; -} - -static void multifd_pages_clear(MultiFDPages_t *pages) -{ - pages->num = 0; - pages->allocated = 0; - pages->packet_num = 0; - pages->block = NULL; - g_free(pages->offset); - pages->offset = NULL; - g_free(pages); -} - -static void multifd_send_fill_packet(MultiFDSendParams *p) -{ - MultiFDPacket_t *packet = p->packet; - int i; - - packet->flags = cpu_to_be32(p->flags); - packet->pages_alloc = cpu_to_be32(p->pages->allocated); - packet->normal_pages = cpu_to_be32(p->normal_num); - packet->next_packet_size = cpu_to_be32(p->next_packet_size); - packet->packet_num = cpu_to_be64(p->packet_num); - - if (p->pages->block) { - strncpy(packet->ramblock, p->pages->block->idstr, 256); - } - - for (i = 0; i < p->normal_num; i++) { - /* there are architectures where ram_addr_t is 32 bit */ - uint64_t temp = p->normal[i]; - - packet->offset[i] = cpu_to_be64(temp); - } -} - -static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) -{ - MultiFDPacket_t *packet = p->packet; - RAMBlock *block; - int i; - - packet->magic = be32_to_cpu(packet->magic); - if (packet->magic != MULTIFD_MAGIC) { - error_setg(errp, "multifd: received packet " - "magic %x and expected magic %x", - packet->magic, MULTIFD_MAGIC); - return -1; - } - - packet->version = be32_to_cpu(packet->version); - if (packet->version != MULTIFD_VERSION) { - error_setg(errp, "multifd: received packet " - "version %u and expected version %u", - packet->version, MULTIFD_VERSION); - return -1; - } - - p->flags = be32_to_cpu(packet->flags); - - packet->pages_alloc = be32_to_cpu(packet->pages_alloc); - /* - * If we received a packet that is 100 times bigger than expected - * just stop migration. It is a magic number. - */ - if (packet->pages_alloc > p->page_count) { - error_setg(errp, "multifd: received packet " - "with size %u and expected a size of %u", - packet->pages_alloc, p->page_count) ; - return -1; - } - - p->normal_num = be32_to_cpu(packet->normal_pages); - if (p->normal_num > packet->pages_alloc) { - error_setg(errp, "multifd: received packet " - "with %u pages and expected maximum pages are %u", - p->normal_num, packet->pages_alloc) ; - return -1; - } - - p->next_packet_size = be32_to_cpu(packet->next_packet_size); - p->packet_num = be64_to_cpu(packet->packet_num); - - if (p->normal_num == 0) { - return 0; - } - - /* make sure that ramblock is 0 terminated */ - packet->ramblock[255] = 0; - block = qemu_ram_block_by_name(packet->ramblock); - if (!block) { - error_setg(errp, "multifd: unknown ram block %s", - packet->ramblock); - return -1; - } - - p->host = block->host; - for (i = 0; i < p->normal_num; i++) { - uint64_t offset = be64_to_cpu(packet->offset[i]); - - if (offset > (block->used_length - p->page_size)) { - error_setg(errp, "multifd: offset too long %" PRIu64 - " (max " RAM_ADDR_FMT ")", - offset, block->used_length); - return -1; - } - p->normal[i] = offset; - } - - return 0; -} - -struct { - MultiFDSendParams *params; - /* array of pages to sent */ - MultiFDPages_t *pages; - /* global number of generated multifd packets */ - uint64_t packet_num; - /* send channels ready */ - QemuSemaphore channels_ready; - /* - * Have we already run terminate threads. There is a race when it - * happens that we got one error while we are exiting. - * We will use atomic operations. Only valid values are 0 and 1. - */ - int exiting; - /* multifd ops */ - MultiFDMethods *ops; -} *multifd_send_state; - -/* - * How we use multifd_send_state->pages and channel->pages? - * - * We create a pages for each channel, and a main one. Each time that - * we need to send a batch of pages we interchange the ones between - * multifd_send_state and the channel that is sending it. There are - * two reasons for that: - * - to not have to do so many mallocs during migration - * - to make easier to know what to free at the end of migration - * - * This way we always know who is the owner of each "pages" struct, - * and we don't need any locking. It belongs to the migration thread - * or to the channel thread. Switching is safe because the migration - * thread is using the channel mutex when changing it, and the channel - * have to had finish with its own, otherwise pending_job can't be - * false. - */ - -static int multifd_send_pages(QEMUFile *f) -{ - int i; - static int next_channel; - MultiFDSendParams *p = NULL; /* make happy gcc */ - MultiFDPages_t *pages = multifd_send_state->pages; - uint64_t transferred; - - if (qatomic_read(&multifd_send_state->exiting)) { - return -1; - } - - qemu_sem_wait(&multifd_send_state->channels_ready); - /* - * next_channel can remain from a previous migration that was - * using more channels, so ensure it doesn't overflow if the - * limit is lower now. - */ - next_channel %= migrate_multifd_channels(); - for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { - p = &multifd_send_state->params[i]; - - qemu_mutex_lock(&p->mutex); - if (p->quit) { - error_report("%s: channel %d has already quit!", __func__, i); - qemu_mutex_unlock(&p->mutex); - return -1; - } - if (!p->pending_job) { - p->pending_job++; - next_channel = (i + 1) % migrate_multifd_channels(); - break; - } - qemu_mutex_unlock(&p->mutex); - } - assert(!p->pages->num); - assert(!p->pages->block); - - p->packet_num = multifd_send_state->packet_num++; - multifd_send_state->pages = p->pages; - p->pages = pages; - transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len; - qemu_file_acct_rate_limit(f, transferred); - ram_counters.multifd_bytes += transferred; - stat64_add(&ram_atomic_counters.transferred, transferred); - qemu_mutex_unlock(&p->mutex); - qemu_sem_post(&p->sem); - - return 1; -} - -int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset) -{ - MultiFDPages_t *pages = multifd_send_state->pages; - bool changed = false; - - if (!pages->block) { - pages->block = block; - } - - if (pages->block == block) { - pages->offset[pages->num] = offset; - pages->num++; - - if (pages->num < pages->allocated) { - return 1; - } - } else { - changed = true; - } - - if (multifd_send_pages(f) < 0) { - return -1; - } - - if (changed) { - return multifd_queue_page(f, block, offset); - } - - return 1; -} - -static void multifd_send_terminate_threads(Error *err) -{ - int i; - - trace_multifd_send_terminate_threads(err != NULL); - - if (err) { - MigrationState *s = migrate_get_current(); - migrate_set_error(s, err); - if (s->state == MIGRATION_STATUS_SETUP || - s->state == MIGRATION_STATUS_PRE_SWITCHOVER || - s->state == MIGRATION_STATUS_DEVICE || - s->state == MIGRATION_STATUS_ACTIVE) { - migrate_set_state(&s->state, s->state, - MIGRATION_STATUS_FAILED); - } - } - - /* - * We don't want to exit each threads twice. Depending on where - * we get the error, or if there are two independent errors in two - * threads at the same time, we can end calling this function - * twice. - */ - if (qatomic_xchg(&multifd_send_state->exiting, 1)) { - return; - } - - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - - qemu_mutex_lock(&p->mutex); - p->quit = true; - qemu_sem_post(&p->sem); - if (p->c) { - qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); - } - qemu_mutex_unlock(&p->mutex); - } -} - -void multifd_save_cleanup(void) -{ - int i; - - if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { - return; - } - multifd_send_terminate_threads(NULL); - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - - if (p->running) { - qemu_thread_join(&p->thread); - } - } - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - Error *local_err = NULL; - - if (p->registered_yank) { - migration_ioc_unregister_yank(p->c); - } - socket_send_channel_destroy(p->c); - p->c = NULL; - qemu_mutex_destroy(&p->mutex); - qemu_sem_destroy(&p->sem); - qemu_sem_destroy(&p->sem_sync); - g_free(p->name); - p->name = NULL; - multifd_pages_clear(p->pages); - p->pages = NULL; - p->packet_len = 0; - g_free(p->packet); - p->packet = NULL; - g_free(p->iov); - p->iov = NULL; - g_free(p->normal); - p->normal = NULL; - multifd_send_state->ops->send_cleanup(p, &local_err); - if (local_err) { - migrate_set_error(migrate_get_current(), local_err); - error_free(local_err); - } - } - qemu_sem_destroy(&multifd_send_state->channels_ready); - g_free(multifd_send_state->params); - multifd_send_state->params = NULL; - multifd_pages_clear(multifd_send_state->pages); - multifd_send_state->pages = NULL; - g_free(multifd_send_state); - multifd_send_state = NULL; -} - -static int multifd_zero_copy_flush(QIOChannel *c) -{ - int ret; - Error *err = NULL; - - ret = qio_channel_flush(c, &err); - if (ret < 0) { - error_report_err(err); - return -1; - } - if (ret == 1) { - dirty_sync_missed_zero_copy(); - } - - return ret; -} - -int multifd_send_sync_main(QEMUFile *f) -{ - int i; - bool flush_zero_copy; - - if (!migrate_use_multifd()) { - return 0; - } - if (multifd_send_state->pages->num) { - if (multifd_send_pages(f) < 0) { - error_report("%s: multifd_send_pages fail", __func__); - return -1; - } - } - - /* - * When using zero-copy, it's necessary to flush the pages before any of - * the pages can be sent again, so we'll make sure the new version of the - * pages will always arrive _later_ than the old pages. - * - * Currently we achieve this by flushing the zero-page requested writes - * per ram iteration, but in the future we could potentially optimize it - * to be less frequent, e.g. only after we finished one whole scanning of - * all the dirty bitmaps. - */ - - flush_zero_copy = migrate_use_zero_copy_send(); - - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - - trace_multifd_send_sync_main_signal(p->id); - - qemu_mutex_lock(&p->mutex); - - if (p->quit) { - error_report("%s: channel %d has already quit", __func__, i); - qemu_mutex_unlock(&p->mutex); - return -1; - } - - p->packet_num = multifd_send_state->packet_num++; - p->flags |= MULTIFD_FLAG_SYNC; - p->pending_job++; - qemu_file_acct_rate_limit(f, p->packet_len); - ram_counters.multifd_bytes += p->packet_len; - stat64_add(&ram_atomic_counters.transferred, p->packet_len); - qemu_mutex_unlock(&p->mutex); - qemu_sem_post(&p->sem); - - if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) { - return -1; - } - } - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - - trace_multifd_send_sync_main_wait(p->id); - qemu_sem_wait(&p->sem_sync); - } - trace_multifd_send_sync_main(multifd_send_state->packet_num); - - return 0; -} - -static void *multifd_send_thread(void *opaque) -{ - MultiFDSendParams *p = opaque; - Error *local_err = NULL; - int ret = 0; - bool use_zero_copy_send = migrate_use_zero_copy_send(); - - trace_multifd_send_thread_start(p->id); - rcu_register_thread(); - - if (multifd_send_initial_packet(p, &local_err) < 0) { - ret = -1; - goto out; - } - /* initial packet */ - p->num_packets = 1; - - while (true) { - qemu_sem_wait(&p->sem); - - if (qatomic_read(&multifd_send_state->exiting)) { - break; - } - qemu_mutex_lock(&p->mutex); - - if (p->pending_job) { - uint64_t packet_num = p->packet_num; - uint32_t flags = p->flags; - p->normal_num = 0; - - if (use_zero_copy_send) { - p->iovs_num = 0; - } else { - p->iovs_num = 1; - } - - for (int i = 0; i < p->pages->num; i++) { - p->normal[p->normal_num] = p->pages->offset[i]; - p->normal_num++; - } - - if (p->normal_num) { - ret = multifd_send_state->ops->send_prepare(p, &local_err); - if (ret != 0) { - qemu_mutex_unlock(&p->mutex); - break; - } - } - multifd_send_fill_packet(p); - p->flags = 0; - p->num_packets++; - p->total_normal_pages += p->normal_num; - p->pages->num = 0; - p->pages->block = NULL; - qemu_mutex_unlock(&p->mutex); - - trace_multifd_send(p->id, packet_num, p->normal_num, flags, - p->next_packet_size); - - if (use_zero_copy_send) { - /* Send header first, without zerocopy */ - ret = qio_channel_write_all(p->c, (void *)p->packet, - p->packet_len, &local_err); - if (ret != 0) { - break; - } - } else { - /* Send header using the same writev call */ - p->iov[0].iov_len = p->packet_len; - p->iov[0].iov_base = p->packet; - } - - ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, NULL, - 0, p->write_flags, &local_err); - if (ret != 0) { - break; - } - - qemu_mutex_lock(&p->mutex); - p->pending_job--; - qemu_mutex_unlock(&p->mutex); - - if (flags & MULTIFD_FLAG_SYNC) { - qemu_sem_post(&p->sem_sync); - } - qemu_sem_post(&multifd_send_state->channels_ready); - } else if (p->quit) { - qemu_mutex_unlock(&p->mutex); - break; - } else { - qemu_mutex_unlock(&p->mutex); - /* sometimes there are spurious wakeups */ - } - } - -out: - if (local_err) { - trace_multifd_send_error(p->id); - multifd_send_terminate_threads(local_err); - error_free(local_err); - } - - /* - * Error happen, I will exit, but I can't just leave, tell - * who pay attention to me. - */ - if (ret != 0) { - qemu_sem_post(&p->sem_sync); - qemu_sem_post(&multifd_send_state->channels_ready); - } - - qemu_mutex_lock(&p->mutex); - p->running = false; - qemu_mutex_unlock(&p->mutex); - - rcu_unregister_thread(); - trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages); - - return NULL; -} - -static bool multifd_channel_connect(MultiFDSendParams *p, - QIOChannel *ioc, - Error *error); - -static void multifd_tls_outgoing_handshake(QIOTask *task, - gpointer opaque) -{ - MultiFDSendParams *p = opaque; - QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); - Error *err = NULL; - - if (qio_task_propagate_error(task, &err)) { - trace_multifd_tls_outgoing_handshake_error(ioc, error_get_pretty(err)); - } else { - trace_multifd_tls_outgoing_handshake_complete(ioc); - } - - if (!multifd_channel_connect(p, ioc, err)) { - /* - * Error happen, mark multifd_send_thread status as 'quit' although it - * is not created, and then tell who pay attention to me. - */ - p->quit = true; - qemu_sem_post(&multifd_send_state->channels_ready); - qemu_sem_post(&p->sem_sync); - } -} - -static void *multifd_tls_handshake_thread(void *opaque) -{ - MultiFDSendParams *p = opaque; - QIOChannelTLS *tioc = QIO_CHANNEL_TLS(p->c); - - qio_channel_tls_handshake(tioc, - multifd_tls_outgoing_handshake, - p, - NULL, - NULL); - return NULL; -} - -static void multifd_tls_channel_connect(MultiFDSendParams *p, - QIOChannel *ioc, - Error **errp) -{ - MigrationState *s = migrate_get_current(); - const char *hostname = s->hostname; - QIOChannelTLS *tioc; - - tioc = migration_tls_client_create(s, ioc, hostname, errp); - if (!tioc) { - return; - } - - object_unref(OBJECT(ioc)); - trace_multifd_tls_outgoing_handshake_start(ioc, tioc, hostname); - qio_channel_set_name(QIO_CHANNEL(tioc), "multifd-tls-outgoing"); - p->c = QIO_CHANNEL(tioc); - qemu_thread_create(&p->thread, "multifd-tls-handshake-worker", - multifd_tls_handshake_thread, p, - QEMU_THREAD_JOINABLE); -} - -static bool multifd_channel_connect(MultiFDSendParams *p, - QIOChannel *ioc, - Error *error) -{ - trace_multifd_set_outgoing_channel( - ioc, object_get_typename(OBJECT(ioc)), - migrate_get_current()->hostname, error); - - if (!error) { - if (migrate_channel_requires_tls_upgrade(ioc)) { - multifd_tls_channel_connect(p, ioc, &error); - if (!error) { - /* - * tls_channel_connect will call back to this - * function after the TLS handshake, - * so we mustn't call multifd_send_thread until then - */ - return true; - } else { - return false; - } - } else { - migration_ioc_register_yank(ioc); - p->registered_yank = true; - p->c = ioc; - qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, - QEMU_THREAD_JOINABLE); - } - return true; - } - - return false; -} - -static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, - QIOChannel *ioc, Error *err) -{ - migrate_set_error(migrate_get_current(), err); - /* Error happen, we need to tell who pay attention to me */ - qemu_sem_post(&multifd_send_state->channels_ready); - qemu_sem_post(&p->sem_sync); - /* - * Although multifd_send_thread is not created, but main migration - * thread neet to judge whether it is running, so we need to mark - * its status. - */ - p->quit = true; - object_unref(OBJECT(ioc)); - error_free(err); -} - -static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) -{ - MultiFDSendParams *p = opaque; - QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); - Error *local_err = NULL; - - trace_multifd_new_send_channel_async(p->id); - if (qio_task_propagate_error(task, &local_err)) { - goto cleanup; - } else { - p->c = QIO_CHANNEL(sioc); - qio_channel_set_delay(p->c, false); - p->running = true; - if (!multifd_channel_connect(p, sioc, local_err)) { - goto cleanup; - } - return; - } - -cleanup: - multifd_new_send_channel_cleanup(p, sioc, local_err); -} - -int multifd_save_setup(Error **errp) -{ - int thread_count; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); - uint8_t i; - - if (!migrate_use_multifd()) { - return 0; - } - if (!migrate_multi_channels_is_allowed()) { - error_setg(errp, "multifd is not supported by current protocol"); - return -1; - } - - thread_count = migrate_multifd_channels(); - multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); - multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); - multifd_send_state->pages = multifd_pages_init(page_count); - qemu_sem_init(&multifd_send_state->channels_ready, 0); - qatomic_set(&multifd_send_state->exiting, 0); - multifd_send_state->ops = multifd_ops[migrate_multifd_compression()]; - - for (i = 0; i < thread_count; i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - - qemu_mutex_init(&p->mutex); - qemu_sem_init(&p->sem, 0); - qemu_sem_init(&p->sem_sync, 0); - p->quit = false; - p->pending_job = 0; - p->id = i; - p->pages = multifd_pages_init(page_count); - p->packet_len = sizeof(MultiFDPacket_t) - + sizeof(uint64_t) * page_count; - p->packet = g_malloc0(p->packet_len); - p->packet->magic = cpu_to_be32(MULTIFD_MAGIC); - p->packet->version = cpu_to_be32(MULTIFD_VERSION); - p->name = g_strdup_printf("multifdsend_%d", i); - /* We need one extra place for the packet header */ - p->iov = g_new0(struct iovec, page_count + 1); - p->normal = g_new0(ram_addr_t, page_count); - p->page_size = qemu_target_page_size(); - p->page_count = page_count; - - if (migrate_use_zero_copy_send()) { - p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; - } else { - p->write_flags = 0; - } - - socket_send_channel_create(multifd_new_send_channel_async, p); - } - - for (i = 0; i < thread_count; i++) { - MultiFDSendParams *p = &multifd_send_state->params[i]; - Error *local_err = NULL; - int ret; - - ret = multifd_send_state->ops->send_setup(p, &local_err); - if (ret) { - error_propagate(errp, local_err); - return ret; - } - } - return 0; -} - -struct { - MultiFDRecvParams *params; - /* number of created threads */ - int count; - /* syncs main thread and channels */ - QemuSemaphore sem_sync; - /* global number of generated multifd packets */ - uint64_t packet_num; - /* multifd ops */ - MultiFDMethods *ops; -} *multifd_recv_state; - -static void multifd_recv_terminate_threads(Error *err) -{ - int i; - - trace_multifd_recv_terminate_threads(err != NULL); - - if (err) { - MigrationState *s = migrate_get_current(); - migrate_set_error(s, err); - if (s->state == MIGRATION_STATUS_SETUP || - s->state == MIGRATION_STATUS_ACTIVE) { - migrate_set_state(&s->state, s->state, - MIGRATION_STATUS_FAILED); - } - } - - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - qemu_mutex_lock(&p->mutex); - p->quit = true; - /* - * We could arrive here for two reasons: - * - normal quit, i.e. everything went fine, just finished - * - error quit: We close the channels so the channel threads - * finish the qio_channel_read_all_eof() - */ - if (p->c) { - qio_channel_shutdown(p->c, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); - } - qemu_mutex_unlock(&p->mutex); - } -} - -int multifd_load_cleanup(Error **errp) -{ - int i; - - if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { - return 0; - } - multifd_recv_terminate_threads(NULL); - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - if (p->running) { - p->quit = true; - /* - * multifd_recv_thread may hung at MULTIFD_FLAG_SYNC handle code, - * however try to wakeup it without harm in cleanup phase. - */ - qemu_sem_post(&p->sem_sync); - qemu_thread_join(&p->thread); - } - } - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - migration_ioc_unregister_yank(p->c); - object_unref(OBJECT(p->c)); - p->c = NULL; - qemu_mutex_destroy(&p->mutex); - qemu_sem_destroy(&p->sem_sync); - g_free(p->name); - p->name = NULL; - p->packet_len = 0; - g_free(p->packet); - p->packet = NULL; - g_free(p->iov); - p->iov = NULL; - g_free(p->normal); - p->normal = NULL; - multifd_recv_state->ops->recv_cleanup(p); - } - qemu_sem_destroy(&multifd_recv_state->sem_sync); - g_free(multifd_recv_state->params); - multifd_recv_state->params = NULL; - g_free(multifd_recv_state); - multifd_recv_state = NULL; - - return 0; -} - -void multifd_recv_sync_main(void) -{ - int i; - - if (!migrate_use_multifd()) { - return; - } - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - trace_multifd_recv_sync_main_wait(p->id); - qemu_sem_wait(&multifd_recv_state->sem_sync); - } - for (i = 0; i < migrate_multifd_channels(); i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - WITH_QEMU_LOCK_GUARD(&p->mutex) { - if (multifd_recv_state->packet_num < p->packet_num) { - multifd_recv_state->packet_num = p->packet_num; - } - } - trace_multifd_recv_sync_main_signal(p->id); - qemu_sem_post(&p->sem_sync); - } - trace_multifd_recv_sync_main(multifd_recv_state->packet_num); -} - -static void *multifd_recv_thread(void *opaque) -{ - MultiFDRecvParams *p = opaque; - Error *local_err = NULL; - int ret; - - trace_multifd_recv_thread_start(p->id); - rcu_register_thread(); - - while (true) { - uint32_t flags; - - if (p->quit) { - break; - } - - ret = qio_channel_read_all_eof(p->c, (void *)p->packet, - p->packet_len, &local_err); - if (ret == 0) { /* EOF */ - break; - } - if (ret == -1) { /* Error */ - break; - } - - qemu_mutex_lock(&p->mutex); - ret = multifd_recv_unfill_packet(p, &local_err); - if (ret) { - qemu_mutex_unlock(&p->mutex); - break; - } - - flags = p->flags; - /* recv methods don't know how to handle the SYNC flag */ - p->flags &= ~MULTIFD_FLAG_SYNC; - trace_multifd_recv(p->id, p->packet_num, p->normal_num, flags, - p->next_packet_size); - p->num_packets++; - p->total_normal_pages += p->normal_num; - qemu_mutex_unlock(&p->mutex); - - if (p->normal_num) { - ret = multifd_recv_state->ops->recv_pages(p, &local_err); - if (ret != 0) { - break; - } - } - - if (flags & MULTIFD_FLAG_SYNC) { - qemu_sem_post(&multifd_recv_state->sem_sync); - qemu_sem_wait(&p->sem_sync); - } - } - - if (local_err) { - multifd_recv_terminate_threads(local_err); - error_free(local_err); - } - qemu_mutex_lock(&p->mutex); - p->running = false; - qemu_mutex_unlock(&p->mutex); - - rcu_unregister_thread(); - trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages); - - return NULL; -} - -int multifd_load_setup(Error **errp) -{ - int thread_count; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); - uint8_t i; - - /* - * Return successfully if multiFD recv state is already initialised - * or multiFD is not enabled. - */ - if (multifd_recv_state || !migrate_use_multifd()) { - return 0; - } - - if (!migrate_multi_channels_is_allowed()) { - error_setg(errp, "multifd is not supported by current protocol"); - return -1; - } - thread_count = migrate_multifd_channels(); - multifd_recv_state = g_malloc0(sizeof(*multifd_recv_state)); - multifd_recv_state->params = g_new0(MultiFDRecvParams, thread_count); - qatomic_set(&multifd_recv_state->count, 0); - qemu_sem_init(&multifd_recv_state->sem_sync, 0); - multifd_recv_state->ops = multifd_ops[migrate_multifd_compression()]; - - for (i = 0; i < thread_count; i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - - qemu_mutex_init(&p->mutex); - qemu_sem_init(&p->sem_sync, 0); - p->quit = false; - p->id = i; - p->packet_len = sizeof(MultiFDPacket_t) - + sizeof(uint64_t) * page_count; - p->packet = g_malloc0(p->packet_len); - p->name = g_strdup_printf("multifdrecv_%d", i); - p->iov = g_new0(struct iovec, page_count); - p->normal = g_new0(ram_addr_t, page_count); - p->page_count = page_count; - p->page_size = qemu_target_page_size(); - } - - for (i = 0; i < thread_count; i++) { - MultiFDRecvParams *p = &multifd_recv_state->params[i]; - Error *local_err = NULL; - int ret; - - ret = multifd_recv_state->ops->recv_setup(p, &local_err); - if (ret) { - error_propagate(errp, local_err); - return ret; - } - } - return 0; -} - -bool multifd_recv_all_channels_created(void) -{ - int thread_count = migrate_multifd_channels(); - - if (!migrate_use_multifd()) { - return true; - } - - if (!multifd_recv_state) { - /* Called before any connections created */ - return false; - } - - return thread_count == qatomic_read(&multifd_recv_state->count); -} - -/* - * Try to receive all multifd channels to get ready for the migration. - * Sets @errp when failing to receive the current channel. - */ -void multifd_recv_new_channel(QIOChannel *ioc, Error **errp) -{ - MultiFDRecvParams *p; - Error *local_err = NULL; - int id; - - id = multifd_recv_initial_packet(ioc, &local_err); - if (id < 0) { - multifd_recv_terminate_threads(local_err); - error_propagate_prepend(errp, local_err, - "failed to receive packet" - " via multifd channel %d: ", - qatomic_read(&multifd_recv_state->count)); - return; - } - trace_multifd_recv_new_channel(id); - - p = &multifd_recv_state->params[id]; - if (p->c != NULL) { - error_setg(&local_err, "multifd: received id '%d' already setup'", - id); - multifd_recv_terminate_threads(local_err); - error_propagate(errp, local_err); - return; - } - p->c = ioc; - object_ref(OBJECT(ioc)); - /* initial packet */ - p->num_packets = 1; - - p->running = true; - qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, - QEMU_THREAD_JOINABLE); - qatomic_inc(&multifd_recv_state->count); -} From e3f37b2ce613c5597cc394800874c8716ea8936a Mon Sep 17 00:00:00 2001 From: Li Zhang Date: Wed, 22 Dec 2021 12:30:48 +0100 Subject: [PATCH 675/814] multifd: cleanup the function multifd_channel_connect Cleanup multifd_channel_connect Signed-off-by: Li Zhang Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/multifd.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index b7ad7002e0..c8132ab7e8 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -843,30 +843,29 @@ static bool multifd_channel_connect(MultiFDSendParams *p, ioc, object_get_typename(OBJECT(ioc)), migrate_get_current()->hostname, error); - if (!error) { - if (migrate_channel_requires_tls_upgrade(ioc)) { - multifd_tls_channel_connect(p, ioc, &error); - if (!error) { - /* - * tls_channel_connect will call back to this - * function after the TLS handshake, - * so we mustn't call multifd_send_thread until then - */ - return true; - } else { - return false; - } - } else { - migration_ioc_register_yank(ioc); - p->registered_yank = true; - p->c = ioc; - qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, - QEMU_THREAD_JOINABLE); - } - return true; + if (error) { + return false; } - - return false; + if (migrate_channel_requires_tls_upgrade(ioc)) { + multifd_tls_channel_connect(p, ioc, &error); + if (!error) { + /* + * tls_channel_connect will call back to this + * function after the TLS handshake, + * so we mustn't call multifd_send_thread until then + */ + return true; + } else { + return false; + } + } else { + migration_ioc_register_yank(ioc); + p->registered_yank = true; + p->c = ioc; + qemu_thread_create(&p->thread, p->name, multifd_send_thread, p, + QEMU_THREAD_JOINABLE); + } + return true; } static void multifd_new_send_channel_cleanup(MultiFDSendParams *p, From bca762c2b90979e8cf1f725cec3ddf888b7b898b Mon Sep 17 00:00:00 2001 From: Li Zhang Date: Thu, 27 Jan 2022 21:02:01 +0100 Subject: [PATCH 676/814] multifd: Remove some redundant code Clean up some unnecessary code Signed-off-by: Li Zhang Signed-off-by: Juan Quintela --- migration/multifd.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index c8132ab7e8..7aa030fb19 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -892,19 +892,15 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) Error *local_err = NULL; trace_multifd_new_send_channel_async(p->id); - if (qio_task_propagate_error(task, &local_err)) { - goto cleanup; - } else { + if (!qio_task_propagate_error(task, &local_err)) { p->c = QIO_CHANNEL(sioc); qio_channel_set_delay(p->c, false); p->running = true; - if (!multifd_channel_connect(p, sioc, local_err)) { - goto cleanup; + if (multifd_channel_connect(p, sioc, local_err)) { + return; } - return; } -cleanup: multifd_new_send_channel_cleanup(p, sioc, local_err); } @@ -1115,10 +1111,7 @@ static void *multifd_recv_thread(void *opaque) ret = qio_channel_read_all_eof(p->c, (void *)p->packet, p->packet_len, &local_err); - if (ret == 0) { /* EOF */ - break; - } - if (ret == -1) { /* Error */ + if (ret == 0 || ret == -1) { /* 0: EOF -1: Error */ break; } From 93e0932b7be2498024cd6ba8446a0fa2cb1769bc Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 7 Feb 2023 15:57:10 -0500 Subject: [PATCH 677/814] linux-headers: Update to v6.1 Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Acked-by: Cornelia Huck Signed-off-by: Juan Quintela --- include/standard-headers/drm/drm_fourcc.h | 34 ++++- include/standard-headers/linux/ethtool.h | 63 +++++++- include/standard-headers/linux/fuse.h | 6 +- .../linux/input-event-codes.h | 1 + include/standard-headers/linux/virtio_blk.h | 19 +++ linux-headers/asm-generic/hugetlb_encode.h | 26 ++-- linux-headers/asm-generic/mman-common.h | 2 + linux-headers/asm-mips/mman.h | 2 + linux-headers/asm-riscv/kvm.h | 4 + linux-headers/linux/kvm.h | 1 + linux-headers/linux/psci.h | 16 +- linux-headers/linux/userfaultfd.h | 4 + linux-headers/linux/vfio.h | 142 ++++++++++++++++++ 13 files changed, 299 insertions(+), 21 deletions(-) diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index 48b620cbef..b868488f93 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -98,18 +98,42 @@ extern "C" { #define DRM_FORMAT_INVALID 0 /* color index */ +#define DRM_FORMAT_C1 fourcc_code('C', '1', ' ', ' ') /* [7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte */ +#define DRM_FORMAT_C2 fourcc_code('C', '2', ' ', ' ') /* [7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte */ +#define DRM_FORMAT_C4 fourcc_code('C', '4', ' ', ' ') /* [7:0] C0:C1 4:4 two pixels/byte */ #define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ -/* 8 bpp Red */ +/* 1 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D1 fourcc_code('D', '1', ' ', ' ') /* [7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte */ + +/* 2 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D2 fourcc_code('D', '2', ' ', ' ') /* [7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte */ + +/* 4 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D4 fourcc_code('D', '4', ' ', ' ') /* [7:0] D0:D1 4:4 two pixels/byte */ + +/* 8 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D8 fourcc_code('D', '8', ' ', ' ') /* [7:0] D */ + +/* 1 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R1 fourcc_code('R', '1', ' ', ' ') /* [7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte */ + +/* 2 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R2 fourcc_code('R', '2', ' ', ' ') /* [7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte */ + +/* 4 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R4 fourcc_code('R', '4', ' ', ' ') /* [7:0] R0:R1 4:4 two pixels/byte */ + +/* 8 bpp Red (direct relationship between channel value and brightness) */ #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ -/* 10 bpp Red */ +/* 10 bpp Red (direct relationship between channel value and brightness) */ #define DRM_FORMAT_R10 fourcc_code('R', '1', '0', ' ') /* [15:0] x:R 6:10 little endian */ -/* 12 bpp Red */ +/* 12 bpp Red (direct relationship between channel value and brightness) */ #define DRM_FORMAT_R12 fourcc_code('R', '1', '2', ' ') /* [15:0] x:R 4:12 little endian */ -/* 16 bpp Red */ +/* 16 bpp Red (direct relationship between channel value and brightness) */ #define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */ /* 16 bpp RG */ @@ -204,7 +228,9 @@ extern "C" { #define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ #define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_AVUY8888 fourcc_code('A', 'V', 'U', 'Y') /* [31:0] A:Cr:Cb:Y 8:8:8:8 little endian */ #define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_XVUY8888 fourcc_code('X', 'V', 'U', 'Y') /* [31:0] X:Cr:Cb:Y 8:8:8:8 little endian */ #define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ #define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 4537da20cc..1dc56cdc0a 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -736,6 +736,51 @@ enum ethtool_module_power_mode { ETHTOOL_MODULE_POWER_MODE_HIGH, }; +/** + * enum ethtool_podl_pse_admin_state - operational state of the PoDL PSE + * functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState + * @ETHTOOL_PODL_PSE_ADMIN_STATE_UNKNOWN: state of PoDL PSE functions are + * unknown + * @ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED: PoDL PSE functions are disabled + * @ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED: PoDL PSE functions are enabled + */ +enum ethtool_podl_pse_admin_state { + ETHTOOL_PODL_PSE_ADMIN_STATE_UNKNOWN = 1, + ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED, + ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED, +}; + +/** + * enum ethtool_podl_pse_pw_d_status - power detection status of the PoDL PSE. + * IEEE 802.3-2018 30.15.1.1.3 aPoDLPSEPowerDetectionStatus: + * @ETHTOOL_PODL_PSE_PW_D_STATUS_UNKNOWN: PoDL PSE + * @ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED: "The enumeration “disabled” is + * asserted true when the PoDL PSE state diagram variable mr_pse_enable is + * false" + * @ETHTOOL_PODL_PSE_PW_D_STATUS_SEARCHING: "The enumeration “searching” is + * asserted true when either of the PSE state diagram variables + * pi_detecting or pi_classifying is true." + * @ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING: "The enumeration “deliveringPower” + * is asserted true when the PoDL PSE state diagram variable pi_powered is + * true." + * @ETHTOOL_PODL_PSE_PW_D_STATUS_SLEEP: "The enumeration “sleep” is asserted + * true when the PoDL PSE state diagram variable pi_sleeping is true." + * @ETHTOOL_PODL_PSE_PW_D_STATUS_IDLE: "The enumeration “idle” is asserted true + * when the logical combination of the PoDL PSE state diagram variables + * pi_prebiased*!pi_sleeping is true." + * @ETHTOOL_PODL_PSE_PW_D_STATUS_ERROR: "The enumeration “error” is asserted + * true when the PoDL PSE state diagram variable overload_held is true." + */ +enum ethtool_podl_pse_pw_d_status { + ETHTOOL_PODL_PSE_PW_D_STATUS_UNKNOWN = 1, + ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED, + ETHTOOL_PODL_PSE_PW_D_STATUS_SEARCHING, + ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING, + ETHTOOL_PODL_PSE_PW_D_STATUS_SLEEP, + ETHTOOL_PODL_PSE_PW_D_STATUS_IDLE, + ETHTOOL_PODL_PSE_PW_D_STATUS_ERROR, +}; + /** * struct ethtool_gstrings - string set for data tagging * @cmd: Command number = %ETHTOOL_GSTRINGS @@ -1840,6 +1885,20 @@ static inline int ethtool_validate_duplex(uint8_t duplex) #define MASTER_SLAVE_STATE_SLAVE 3 #define MASTER_SLAVE_STATE_ERR 4 +/* These are used to throttle the rate of data on the phy interface when the + * native speed of the interface is higher than the link speed. These should + * not be used for phy interfaces which natively support multiple speeds (e.g. + * MII or SGMII). + */ +/* No rate matching performed. */ +#define RATE_MATCH_NONE 0 +/* The phy sends pause frames to throttle the MAC. */ +#define RATE_MATCH_PAUSE 1 +/* The phy asserts CRS to prevent the MAC from transmitting. */ +#define RATE_MATCH_CRS 2 +/* The MAC is programmed with a sufficiently-large IPG. */ +#define RATE_MATCH_OPEN_LOOP 3 + /* Which connector port. */ #define PORT_TP 0x00 #define PORT_AUI 0x01 @@ -2033,8 +2092,8 @@ enum ethtool_reset_flags { * reported consistently by PHYLIB. Read-only. * @master_slave_cfg: Master/slave port mode. * @master_slave_state: Master/slave port state. + * @rate_matching: Rate adaptation performed by the PHY * @reserved: Reserved for future use; see the note on reserved space. - * @reserved1: Reserved for future use; see the note on reserved space. * @link_mode_masks: Variable length bitmaps. * * If autonegotiation is disabled, the speed and @duplex represent the @@ -2085,7 +2144,7 @@ struct ethtool_link_settings { uint8_t transceiver; uint8_t master_slave_cfg; uint8_t master_slave_state; - uint8_t reserved1[1]; + uint8_t rate_matching; uint32_t reserved[7]; uint32_t link_mode_masks[]; /* layout of link_mode_masks fields: diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h index bda06258be..713d259768 100644 --- a/include/standard-headers/linux/fuse.h +++ b/include/standard-headers/linux/fuse.h @@ -194,6 +194,9 @@ * - add FUSE_SECURITY_CTX init flag * - add security context to create, mkdir, symlink, and mknod requests * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX + * + * 7.37 + * - add FUSE_TMPFILE */ #ifndef _LINUX_FUSE_H @@ -225,7 +228,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 36 +#define FUSE_KERNEL_MINOR_VERSION 37 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -533,6 +536,7 @@ enum fuse_opcode { FUSE_SETUPMAPPING = 48, FUSE_REMOVEMAPPING = 49, FUSE_SYNCFS = 50, + FUSE_TMPFILE = 51, /* CUSE specific operations */ CUSE_INIT = 4096, diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index 50790aee5a..815f7a1dff 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -862,6 +862,7 @@ #define ABS_TOOL_WIDTH 0x1c #define ABS_VOLUME 0x20 +#define ABS_PROFILE 0x21 #define ABS_MISC 0x28 diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard-headers/linux/virtio_blk.h index 2dcc90826a..e81715cd70 100644 --- a/include/standard-headers/linux/virtio_blk.h +++ b/include/standard-headers/linux/virtio_blk.h @@ -40,6 +40,7 @@ #define VIRTIO_BLK_F_MQ 12 /* support more than one vq */ #define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */ #define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */ +#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */ /* Legacy feature bits */ #ifndef VIRTIO_BLK_NO_LEGACY @@ -119,6 +120,21 @@ struct virtio_blk_config { uint8_t write_zeroes_may_unmap; uint8_t unused1[3]; + + /* the next 3 entries are guarded by VIRTIO_BLK_F_SECURE_ERASE */ + /* + * The maximum secure erase sectors (in 512-byte sectors) for + * one segment. + */ + __virtio32 max_secure_erase_sectors; + /* + * The maximum number of secure erase segments in a + * secure erase command. + */ + __virtio32 max_secure_erase_seg; + /* Secure erase commands must be aligned to this number of sectors. */ + __virtio32 secure_erase_sector_alignment; + } QEMU_PACKED; /* @@ -153,6 +169,9 @@ struct virtio_blk_config { /* Write zeroes command */ #define VIRTIO_BLK_T_WRITE_ZEROES 13 +/* Secure erase command */ +#define VIRTIO_BLK_T_SECURE_ERASE 14 + #ifndef VIRTIO_BLK_NO_LEGACY /* Barrier before this op. */ #define VIRTIO_BLK_T_BARRIER 0x80000000 diff --git a/linux-headers/asm-generic/hugetlb_encode.h b/linux-headers/asm-generic/hugetlb_encode.h index 4f3d5aaa11..de687009bf 100644 --- a/linux-headers/asm-generic/hugetlb_encode.h +++ b/linux-headers/asm-generic/hugetlb_encode.h @@ -20,18 +20,18 @@ #define HUGETLB_FLAG_ENCODE_SHIFT 26 #define HUGETLB_FLAG_ENCODE_MASK 0x3f -#define HUGETLB_FLAG_ENCODE_16KB (14 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_64KB (16 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_512KB (19 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_1MB (20 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_2MB (21 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_8MB (23 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_16MB (24 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_32MB (25 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_256MB (28 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_512MB (29 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_1GB (30 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_2GB (31 << HUGETLB_FLAG_ENCODE_SHIFT) -#define HUGETLB_FLAG_ENCODE_16GB (34 << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_16KB (14U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_64KB (16U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_512KB (19U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_1MB (20U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_2MB (21U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_8MB (23U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_16MB (24U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_32MB (25U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_256MB (28U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_512MB (29U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_1GB (30U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_2GB (31U << HUGETLB_FLAG_ENCODE_SHIFT) +#define HUGETLB_FLAG_ENCODE_16GB (34U << HUGETLB_FLAG_ENCODE_SHIFT) #endif /* _ASM_GENERIC_HUGETLB_ENCODE_H_ */ diff --git a/linux-headers/asm-generic/mman-common.h b/linux-headers/asm-generic/mman-common.h index 6c1aa92a92..6ce1f1ceb4 100644 --- a/linux-headers/asm-generic/mman-common.h +++ b/linux-headers/asm-generic/mman-common.h @@ -77,6 +77,8 @@ #define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ +#define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/asm-mips/mman.h b/linux-headers/asm-mips/mman.h index 1be428663c..c6e1fc77c9 100644 --- a/linux-headers/asm-mips/mman.h +++ b/linux-headers/asm-mips/mman.h @@ -103,6 +103,8 @@ #define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */ +#define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h index 7351417afd..8985ff234c 100644 --- a/linux-headers/asm-riscv/kvm.h +++ b/linux-headers/asm-riscv/kvm.h @@ -48,6 +48,7 @@ struct kvm_sregs { /* CONFIG registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ struct kvm_riscv_config { unsigned long isa; + unsigned long zicbom_block_size; }; /* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ @@ -98,6 +99,9 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_M, KVM_RISCV_ISA_EXT_SVPBMT, KVM_RISCV_ISA_EXT_SSTC, + KVM_RISCV_ISA_EXT_SVINVAL, + KVM_RISCV_ISA_EXT_ZIHINTPAUSE, + KVM_RISCV_ISA_EXT_ZICBOM, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index ebdafa576d..b2783c5202 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1175,6 +1175,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 #define KVM_CAP_S390_ZPCI_OP 221 #define KVM_CAP_S390_CPU_TOPOLOGY 222 +#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/linux-headers/linux/psci.h b/linux-headers/linux/psci.h index 213b2a0f70..e60dfd8907 100644 --- a/linux-headers/linux/psci.h +++ b/linux-headers/linux/psci.h @@ -48,12 +48,26 @@ #define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) #define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) +#define PSCI_1_0_FN_CPU_FREEZE PSCI_0_2_FN(11) +#define PSCI_1_0_FN_CPU_DEFAULT_SUSPEND PSCI_0_2_FN(12) +#define PSCI_1_0_FN_NODE_HW_STATE PSCI_0_2_FN(13) #define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14) #define PSCI_1_0_FN_SET_SUSPEND_MODE PSCI_0_2_FN(15) -#define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_0_2_FN(18) +#define PSCI_1_0_FN_STAT_RESIDENCY PSCI_0_2_FN(16) +#define PSCI_1_0_FN_STAT_COUNT PSCI_0_2_FN(17) +#define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_0_2_FN(18) +#define PSCI_1_1_FN_MEM_PROTECT PSCI_0_2_FN(19) +#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN(19) + +#define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND PSCI_0_2_FN64(12) +#define PSCI_1_0_FN64_NODE_HW_STATE PSCI_0_2_FN64(13) #define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) +#define PSCI_1_0_FN64_STAT_RESIDENCY PSCI_0_2_FN64(16) +#define PSCI_1_0_FN64_STAT_COUNT PSCI_0_2_FN64(17) + #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18) +#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN64(19) /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index a3a377cd44..ba5d0df52f 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -12,6 +12,10 @@ #include +/* ioctls for /dev/userfaultfd */ +#define USERFAULTFD_IOC 0xAA +#define USERFAULTFD_IOC_NEW _IO(USERFAULTFD_IOC, 0x00) + /* * If the UFFDIO_API is upgraded someday, the UFFDIO_UNREGISTER and * UFFDIO_WAKE ioctls should be defined as _IOW and not as _IOR. In diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index ede44b5572..bee7e42198 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -986,6 +986,148 @@ enum vfio_device_mig_state { VFIO_DEVICE_STATE_RUNNING_P2P = 5, }; +/* + * Upon VFIO_DEVICE_FEATURE_SET, allow the device to be moved into a low power + * state with the platform-based power management. Device use of lower power + * states depends on factors managed by the runtime power management core, + * including system level support and coordinating support among dependent + * devices. Enabling device low power entry does not guarantee lower power + * usage by the device, nor is a mechanism provided through this feature to + * know the current power state of the device. If any device access happens + * (either from the host or through the vfio uAPI) when the device is in the + * low power state, then the host will move the device out of the low power + * state as necessary prior to the access. Once the access is completed, the + * device may re-enter the low power state. For single shot low power support + * with wake-up notification, see + * VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP below. Access to mmap'd + * device regions is disabled on LOW_POWER_ENTRY and may only be resumed after + * calling LOW_POWER_EXIT. + */ +#define VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY 3 + +/* + * This device feature has the same behavior as + * VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY with the exception that the user + * provides an eventfd for wake-up notification. When the device moves out of + * the low power state for the wake-up, the host will not allow the device to + * re-enter a low power state without a subsequent user call to one of the low + * power entry device feature IOCTLs. Access to mmap'd device regions is + * disabled on LOW_POWER_ENTRY_WITH_WAKEUP and may only be resumed after the + * low power exit. The low power exit can happen either through LOW_POWER_EXIT + * or through any other access (where the wake-up notification has been + * generated). The access to mmap'd device regions will not trigger low power + * exit. + * + * The notification through the provided eventfd will be generated only when + * the device has entered and is resumed from a low power state after + * calling this device feature IOCTL. A device that has not entered low power + * state, as managed through the runtime power management core, will not + * generate a notification through the provided eventfd on access. Calling the + * LOW_POWER_EXIT feature is optional in the case where notification has been + * signaled on the provided eventfd that a resume from low power has occurred. + */ +struct vfio_device_low_power_entry_with_wakeup { + __s32 wakeup_eventfd; + __u32 reserved; +}; + +#define VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP 4 + +/* + * Upon VFIO_DEVICE_FEATURE_SET, disallow use of device low power states as + * previously enabled via VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY or + * VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP device features. + * This device feature IOCTL may itself generate a wakeup eventfd notification + * in the latter case if the device had previously entered a low power state. + */ +#define VFIO_DEVICE_FEATURE_LOW_POWER_EXIT 5 + +/* + * Upon VFIO_DEVICE_FEATURE_SET start/stop device DMA logging. + * VFIO_DEVICE_FEATURE_PROBE can be used to detect if the device supports + * DMA logging. + * + * DMA logging allows a device to internally record what DMAs the device is + * initiating and report them back to userspace. It is part of the VFIO + * migration infrastructure that allows implementing dirty page tracking + * during the pre copy phase of live migration. Only DMA WRITEs are logged, + * and this API is not connected to VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE. + * + * When DMA logging is started a range of IOVAs to monitor is provided and the + * device can optimize its logging to cover only the IOVA range given. Each + * DMA that the device initiates inside the range will be logged by the device + * for later retrieval. + * + * page_size is an input that hints what tracking granularity the device + * should try to achieve. If the device cannot do the hinted page size then + * it's the driver choice which page size to pick based on its support. + * On output the device will return the page size it selected. + * + * ranges is a pointer to an array of + * struct vfio_device_feature_dma_logging_range. + * + * The core kernel code guarantees to support by minimum num_ranges that fit + * into a single kernel page. User space can try higher values but should give + * up if the above can't be achieved as of some driver limitations. + * + * A single call to start device DMA logging can be issued and a matching stop + * should follow at the end. Another start is not allowed in the meantime. + */ +struct vfio_device_feature_dma_logging_control { + __aligned_u64 page_size; + __u32 num_ranges; + __u32 __reserved; + __aligned_u64 ranges; +}; + +struct vfio_device_feature_dma_logging_range { + __aligned_u64 iova; + __aligned_u64 length; +}; + +#define VFIO_DEVICE_FEATURE_DMA_LOGGING_START 6 + +/* + * Upon VFIO_DEVICE_FEATURE_SET stop device DMA logging that was started + * by VFIO_DEVICE_FEATURE_DMA_LOGGING_START + */ +#define VFIO_DEVICE_FEATURE_DMA_LOGGING_STOP 7 + +/* + * Upon VFIO_DEVICE_FEATURE_GET read back and clear the device DMA log + * + * Query the device's DMA log for written pages within the given IOVA range. + * During querying the log is cleared for the IOVA range. + * + * bitmap is a pointer to an array of u64s that will hold the output bitmap + * with 1 bit reporting a page_size unit of IOVA. The mapping of IOVA to bits + * is given by: + * bitmap[(addr - iova)/page_size] & (1ULL << (addr % 64)) + * + * The input page_size can be any power of two value and does not have to + * match the value given to VFIO_DEVICE_FEATURE_DMA_LOGGING_START. The driver + * will format its internal logging to match the reporting page size, possibly + * by replicating bits if the internal page size is lower than requested. + * + * The LOGGING_REPORT will only set bits in the bitmap and never clear or + * perform any initialization of the user provided bitmap. + * + * If any error is returned userspace should assume that the dirty log is + * corrupted. Error recovery is to consider all memory dirty and try to + * restart the dirty tracking, or to abort/restart the whole migration. + * + * If DMA logging is not enabled, an error will be returned. + * + */ +struct vfio_device_feature_dma_logging_report { + __aligned_u64 iova; + __aligned_u64 length; + __aligned_u64 page_size; + __aligned_u64 bitmap; +}; + +#define VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT 8 + /* -------- API for Type1 VFIO IOMMU -------- */ /** From c40c0463413b941c13fe5f99a90c02d7d6584828 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 7 Feb 2023 15:57:11 -0500 Subject: [PATCH 678/814] util/userfaultfd: Support /dev/userfaultfd Teach QEMU to use /dev/userfaultfd when it existed and fallback to the system call if either it's not there or doesn't have enough permission. Firstly, as long as the app has permission to access /dev/userfaultfd, it always have the ability to trap kernel faults which QEMU mostly wants. Meanwhile, in some context (e.g. containers) the userfaultfd syscall can be forbidden, so it can be the major way to use postcopy in a restricted environment with strict seccomp setup. Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- util/trace-events | 1 + util/userfaultfd.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/util/trace-events b/util/trace-events index c8f53d7d9f..16f78d8fe5 100644 --- a/util/trace-events +++ b/util/trace-events @@ -93,6 +93,7 @@ qemu_vfio_region_info(const char *desc, uint64_t region_ofs, uint64_t region_siz qemu_vfio_pci_map_bar(int index, uint64_t region_ofs, uint64_t region_size, int ofs, void *host) "map region bar#%d addr 0x%"PRIx64" size 0x%"PRIx64" ofs 0x%x host %p" #userfaultfd.c +uffd_detect_open_mode(int mode) "%d" uffd_query_features_nosys(int err) "errno: %i" uffd_query_features_api_failed(int err) "errno: %i" uffd_create_fd_nosys(int err) "errno: %i" diff --git a/util/userfaultfd.c b/util/userfaultfd.c index 4953b3137d..fdff4867e8 100644 --- a/util/userfaultfd.c +++ b/util/userfaultfd.c @@ -18,10 +18,42 @@ #include #include #include +#include + +typedef enum { + UFFD_UNINITIALIZED = 0, + UFFD_USE_DEV_PATH, + UFFD_USE_SYSCALL, +} uffd_open_mode; int uffd_open(int flags) { #if defined(__NR_userfaultfd) + static uffd_open_mode open_mode; + static int uffd_dev; + + /* Detect how to generate uffd desc when run the 1st time */ + if (open_mode == UFFD_UNINITIALIZED) { + /* + * Make /dev/userfaultfd the default approach because it has better + * permission controls, meanwhile allows kernel faults without any + * privilege requirement (e.g. SYS_CAP_PTRACE). + */ + uffd_dev = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); + if (uffd_dev >= 0) { + open_mode = UFFD_USE_DEV_PATH; + } else { + /* Fallback to the system call */ + open_mode = UFFD_USE_SYSCALL; + } + trace_uffd_detect_open_mode(open_mode); + } + + if (open_mode == UFFD_USE_DEV_PATH) { + assert(uffd_dev >= 0); + return ioctl(uffd_dev, USERFAULTFD_IOC_NEW, flags); + } + return syscall(__NR_userfaultfd, flags); #else return -EINVAL; From 51efd36faf2553d9f311cece14198c2ba7ece991 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 21 Jun 2022 13:20:35 +0200 Subject: [PATCH 679/814] migration: Simplify ram_find_and_save_block() We will need later that find_dirty_block() return errors, so simplify the loop. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/ram.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index b966e148c2..dd809fec1f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2542,7 +2542,6 @@ static int ram_find_and_save_block(RAMState *rs) { PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; int pages = 0; - bool again, found; /* No dirty page as there is zero RAM */ if (!ram_bytes_total()) { @@ -2564,18 +2563,17 @@ static int ram_find_and_save_block(RAMState *rs) pss_init(pss, rs->last_seen_block, rs->last_page); do { - again = true; - found = get_queued_page(rs, pss); - - if (!found) { + if (!get_queued_page(rs, pss)) { /* priority queue empty, so just search for something dirty */ - found = find_dirty_block(rs, pss, &again); + bool again = true; + if (!find_dirty_block(rs, pss, &again)) { + if (!again) { + break; + } + } } - - if (found) { - pages = ram_save_host_page(rs, pss); - } - } while (!pages && again); + pages = ram_save_host_page(rs, pss); + } while (!pages); rs->last_seen_block = pss->block; rs->last_page = pss->page; From 31e2ac742b6235cb5002ddd89bfbbf291e8923e3 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 21 Jun 2022 13:29:36 +0200 Subject: [PATCH 680/814] migration: Make find_dirty_block() return a single parameter We used to return two bools, just return a single int with the following meaning: old return / again / new return false false PAGE_ALL_CLEAN false true PAGE_TRY_AGAIN true true PAGE_DIRTY_FOUND /* We don't care about again at all */ Signed-off-by: Juan Quintela --- migration/ram.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index dd809fec1f..cf577fce5c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1546,17 +1546,23 @@ retry: return pages; } +#define PAGE_ALL_CLEAN 0 +#define PAGE_TRY_AGAIN 1 +#define PAGE_DIRTY_FOUND 2 /** * find_dirty_block: find the next dirty page and update any state * associated with the search process. * - * Returns true if a page is found + * Returns: + * PAGE_ALL_CLEAN: no dirty page found, give up + * PAGE_TRY_AGAIN: no dirty page found, retry for next block + * PAGE_DIRTY_FOUND: dirty page found * * @rs: current RAM state * @pss: data about the state of the current dirty page scan * @again: set to false if the search has scanned the whole of RAM */ -static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) +static int find_dirty_block(RAMState *rs, PageSearchStatus *pss) { /* Update pss->page for the next dirty bit in ramblock */ pss_find_next_dirty(pss); @@ -1567,8 +1573,7 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) * We've been once around the RAM and haven't found anything. * Give up. */ - *again = false; - return false; + return PAGE_ALL_CLEAN; } if (!offset_in_ramblock(pss->block, ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)) { @@ -1597,13 +1602,10 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) } } /* Didn't find anything this time, but try again on the new block */ - *again = true; - return false; + return PAGE_TRY_AGAIN; } else { - /* Can go around again, but... */ - *again = true; - /* We've found something so probably don't need to */ - return true; + /* We've found something */ + return PAGE_DIRTY_FOUND; } } @@ -2562,18 +2564,23 @@ static int ram_find_and_save_block(RAMState *rs) pss_init(pss, rs->last_seen_block, rs->last_page); - do { + while (true){ if (!get_queued_page(rs, pss)) { /* priority queue empty, so just search for something dirty */ - bool again = true; - if (!find_dirty_block(rs, pss, &again)) { - if (!again) { + int res = find_dirty_block(rs, pss); + if (res != PAGE_DIRTY_FOUND) { + if (res == PAGE_ALL_CLEAN) { break; + } else if (res == PAGE_TRY_AGAIN) { + continue; } } } pages = ram_save_host_page(rs, pss); - } while (!pages); + if (pages) { + break; + } + } rs->last_seen_block = pss->block; rs->last_page = pss->page; From 8008a272d6b3aa4ba5a21c70786e107df65b9b51 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 10 May 2022 19:18:19 +0200 Subject: [PATCH 681/814] migration: Split ram_bytes_total_common() in two functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is just a big if in the middle of the function, and we need two functions anways. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Juan Quintela --- Reindent to make Phillipe happy (and CODING_STYLE) --- migration/ram.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index cf577fce5c..1727fe5ef6 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2601,28 +2601,30 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero) } } -static uint64_t ram_bytes_total_common(bool count_ignored) +static uint64_t ram_bytes_total_with_ignored(void) { RAMBlock *block; uint64_t total = 0; RCU_READ_LOCK_GUARD(); - if (count_ignored) { - RAMBLOCK_FOREACH_MIGRATABLE(block) { - total += block->used_length; - } - } else { - RAMBLOCK_FOREACH_NOT_IGNORED(block) { - total += block->used_length; - } + RAMBLOCK_FOREACH_MIGRATABLE(block) { + total += block->used_length; } return total; } uint64_t ram_bytes_total(void) { - return ram_bytes_total_common(false); + RAMBlock *block; + uint64_t total = 0; + + RCU_READ_LOCK_GUARD(); + + RAMBLOCK_FOREACH_NOT_IGNORED(block) { + total += block->used_length; + } + return total; } static void xbzrle_load_setup(void) @@ -3227,7 +3229,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque) (*rsp)->pss[RAM_CHANNEL_PRECOPY].pss_channel = f; WITH_RCU_READ_LOCK_GUARD() { - qemu_put_be64(f, ram_bytes_total_common(true) | RAM_SAVE_FLAG_MEM_SIZE); + qemu_put_be64(f, ram_bytes_total_with_ignored() + | RAM_SAVE_FLAG_MEM_SIZE); RAMBLOCK_FOREACH_MIGRATABLE(block) { qemu_put_byte(f, strlen(block->idstr)); From 8d80e1951e57f79ab3d4c156ba8eb71592f81b4c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 10 May 2022 19:37:36 +0200 Subject: [PATCH 682/814] migration: Calculate ram size once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are recalculating ram size continously, when we know that it don't change during migration. Create a field in RAMState to track it. Signed-off-by: Juan Quintela Reviewed-by: Philippe Mathieu-Daudé --- migration/ram.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 1727fe5ef6..6abfe075f2 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -330,6 +330,8 @@ struct RAMState { PageSearchStatus pss[RAM_CHANNEL_MAX]; /* UFFD file descriptor, used in 'write-tracking' migration */ int uffdio_fd; + /* total ram size in bytes */ + uint64_t ram_bytes_total; /* Last block that we have visited searching for dirty pages */ RAMBlock *last_seen_block; /* Last dirty target page we have sent */ @@ -2546,7 +2548,7 @@ static int ram_find_and_save_block(RAMState *rs) int pages = 0; /* No dirty page as there is zero RAM */ - if (!ram_bytes_total()) { + if (!rs->ram_bytes_total) { return pages; } @@ -3009,13 +3011,14 @@ static int ram_state_init(RAMState **rsp) qemu_mutex_init(&(*rsp)->bitmap_mutex); qemu_mutex_init(&(*rsp)->src_page_req_mutex); QSIMPLEQ_INIT(&(*rsp)->src_page_requests); + (*rsp)->ram_bytes_total = ram_bytes_total(); /* * Count the total number of pages used by ram blocks not including any * gaps due to alignment or unplugs. * This must match with the initial values of dirty bitmap. */ - (*rsp)->migration_dirty_pages = ram_bytes_total() >> TARGET_PAGE_BITS; + (*rsp)->migration_dirty_pages = (*rsp)->ram_bytes_total >> TARGET_PAGE_BITS; ram_state_reset(*rsp); return 0; From 4010ba388d9691cfba3762fce5b23c336abc98ba Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 15 Dec 2021 20:10:39 +0100 Subject: [PATCH 683/814] migration: Make ram_save_target_page() a pointer We are going to create a new function for multifd latest in the series. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert --- migration/ram.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 6abfe075f2..0890816a30 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -452,6 +452,13 @@ void dirty_sync_missed_zero_copy(void) ram_counters.dirty_sync_missed_zero_copy++; } +struct MigrationOps { + int (*ram_save_target_page)(RAMState *rs, PageSearchStatus *pss); +}; +typedef struct MigrationOps MigrationOps; + +MigrationOps *migration_ops; + CompressionStats compression_counters; struct CompressParam { @@ -2295,14 +2302,14 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss, } /** - * ram_save_target_page: save one target page + * ram_save_target_page_legacy: save one target page * * Returns the number of pages written * * @rs: current RAM state * @pss: data about the page we want to send */ -static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) +static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss) { RAMBlock *block = pss->block; ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; @@ -2428,7 +2435,7 @@ static int ram_save_host_page_urgent(PageSearchStatus *pss) if (page_dirty) { /* Be strict to return code; it must be 1, or what else? */ - if (ram_save_target_page(rs, pss) != 1) { + if (migration_ops->ram_save_target_page(rs, pss) != 1) { error_report_once("%s: ram_save_target_page failed", __func__); ret = -1; goto out; @@ -2497,7 +2504,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) if (preempt_active) { qemu_mutex_unlock(&rs->bitmap_mutex); } - tmppages = ram_save_target_page(rs, pss); + tmppages = migration_ops->ram_save_target_page(rs, pss); if (tmppages >= 0) { pages += tmppages; /* @@ -2697,6 +2704,8 @@ static void ram_save_cleanup(void *opaque) xbzrle_cleanup(); compress_threads_save_cleanup(); ram_state_cleanup(rsp); + g_free(migration_ops); + migration_ops = NULL; } static void ram_state_reset(RAMState *rs) @@ -3252,6 +3261,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque) ram_control_before_iterate(f, RAM_CONTROL_SETUP); ram_control_after_iterate(f, RAM_CONTROL_SETUP); + migration_ops = g_malloc0(sizeof(MigrationOps)); + migration_ops->ram_save_target_page = ram_save_target_page_legacy; ret = multifd_send_sync_main(f); if (ret < 0) { return ret; From e26470501271adf22e4f37d218c2164884ae96fb Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 9 Feb 2023 14:29:45 +0100 Subject: [PATCH 684/814] migration: I messed state_pending_exact/estimate I called the helper function from the wrong top level function. This code was introduced in: commit c8df4a7aeffcb46020f610526eea621fa5b0cd47 Author: Juan Quintela Date: Mon Oct 3 02:00:03 2022 +0200 migration: Split save_live_pending() into state_pending_* We split the function into to: - state_pending_estimate: We estimate the remaining state size without stopping the machine. - state pending_exact: We calculate the exact amount of remaining state. Thanks to Avihai Horon for finding it. Fixes:c8df4a7aeffcb46020f610526eea621fa5b0cd47 When we introduced that patch, we enden calling state_pending_estimate() helper from qemu_savevm_statepending_exact() and state_pending_exact() helper from qemu_savevm_statepending_estimate() This patch fixes it. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/savevm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index e9cf4999ad..ce181e21e1 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1552,7 +1552,7 @@ void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, *res_postcopy_only = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - if (!se->ops || !se->ops->state_pending_exact) { + if (!se->ops || !se->ops->state_pending_estimate) { continue; } if (se->ops->is_active) { @@ -1560,9 +1560,9 @@ void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, continue; } } - se->ops->state_pending_exact(se->opaque, - res_precopy_only, res_compatible, - res_postcopy_only); + se->ops->state_pending_estimate(se->opaque, + res_precopy_only, res_compatible, + res_postcopy_only); } } @@ -1577,7 +1577,7 @@ void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, *res_postcopy_only = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - if (!se->ops || !se->ops->state_pending_estimate) { + if (!se->ops || !se->ops->state_pending_exact) { continue; } if (se->ops->is_active) { @@ -1585,9 +1585,9 @@ void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, continue; } } - se->ops->state_pending_estimate(se->opaque, - res_precopy_only, res_compatible, - res_postcopy_only); + se->ops->state_pending_exact(se->opaque, + res_precopy_only, res_compatible, + res_postcopy_only); } } From 04ffce137b6d85ab4e7687e54e4dffcef0a9ab99 Mon Sep 17 00:00:00 2001 From: ling xu Date: Wed, 16 Nov 2022 23:29:22 +0800 Subject: [PATCH 685/814] AVX512 support for xbzrle_encode_buffer This commit is the same with [PATCH v6 1/2], and provides avx512 support for xbzrle_encode_buffer function to accelerate xbzrle encoding speed. Runtime check of avx512 support and benchmark for this feature are added. Compared with C version of xbzrle_encode_buffer function, avx512 version can achieve 50%-70% performance improvement on benchmarking. In addition, if dirty data is randomly located in 4K page, the avx512 version can achieve almost 140% performance gain. Signed-off-by: ling xu Co-authored-by: Zhou Zhao Co-authored-by: Jun Jin Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- meson.build | 17 +++++ meson_options.txt | 2 + migration/ram.c | 34 +++++++++- migration/xbzrle.c | 124 ++++++++++++++++++++++++++++++++++ migration/xbzrle.h | 4 ++ scripts/meson-buildoptions.sh | 3 + 6 files changed, 181 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 4ba3bf3431..c626ccfa82 100644 --- a/meson.build +++ b/meson.build @@ -2351,6 +2351,22 @@ config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ int main(int argc, char *argv[]) { return bar(argv[argc - 1]); } '''), error_message: 'AVX512F not available').allowed()) +config_host_data.set('CONFIG_AVX512BW_OPT', get_option('avx512bw') \ + .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512BW') \ + .require(cc.links(''' + #pragma GCC push_options + #pragma GCC target("avx512bw") + #include + #include + static int bar(void *a) { + + __m512i *x = a; + __m512i res= _mm512_abs_epi8(*x); + return res[1]; + } + int main(int argc, char *argv[]) { return bar(argv[0]); } + '''), error_message: 'AVX512BW not available').allowed()) + have_pvrdma = get_option('pvrdma') \ .require(rdma.found(), error_message: 'PVRDMA requires OpenFabrics libraries') \ .require(cc.compiles(gnu_source_prefix + ''' @@ -3783,6 +3799,7 @@ summary_info += {'debug stack usage': get_option('debug_stack_usage')} summary_info += {'mutex debugging': get_option('debug_mutex')} summary_info += {'memory allocator': get_option('malloc')} summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} +summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')} summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} summary_info += {'gprof enabled': get_option('gprof')} summary_info += {'gcov': get_option('b_coverage')} diff --git a/meson_options.txt b/meson_options.txt index 559a571b6b..e5f199119e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -104,6 +104,8 @@ option('avx2', type: 'feature', value: 'auto', description: 'AVX2 optimizations') option('avx512f', type: 'feature', value: 'disabled', description: 'AVX512F optimizations') +option('avx512bw', type: 'feature', value: 'auto', + description: 'AVX512BW optimizations') option('keyring', type: 'feature', value: 'auto', description: 'Linux keyring support') diff --git a/migration/ram.c b/migration/ram.c index 0890816a30..18ac68b181 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -83,6 +83,34 @@ /* 0x80 is reserved in migration.h start with 0x100 next */ #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 +int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int, + uint8_t *, int) = xbzrle_encode_buffer; +#if defined(CONFIG_AVX512BW_OPT) +#include "qemu/cpuid.h" +static void __attribute__((constructor)) init_cpu_flag(void) +{ + unsigned max = __get_cpuid_max(0, NULL); + int a, b, c, d; + if (max >= 1) { + __cpuid(1, a, b, c, d); + /* We must check that AVX is not just available, but usable. */ + if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { + int bv; + __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); + __cpuid_count(7, 0, a, b, c, d); + /* 0xe6: + * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 + * and ZMM16-ZMM31 state are enabled by OS) + * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) + */ + if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { + xbzrle_encode_buffer_func = xbzrle_encode_buffer_avx512; + } + } + } +} +#endif + XBZRLECacheStats xbzrle_counters; /* used by the search for pages to send */ @@ -806,9 +834,9 @@ static int save_xbzrle_page(RAMState *rs, PageSearchStatus *pss, memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE); /* XBZRLE encoding (if there is no overflow) */ - encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf, - TARGET_PAGE_SIZE, XBZRLE.encoded_buf, - TARGET_PAGE_SIZE); + encoded_len = xbzrle_encode_buffer_func(prev_cached_page, XBZRLE.current_buf, + TARGET_PAGE_SIZE, XBZRLE.encoded_buf, + TARGET_PAGE_SIZE); /* * Update the cache contents, so that it corresponds to the data diff --git a/migration/xbzrle.c b/migration/xbzrle.c index 1ba482ded9..05366e86c0 100644 --- a/migration/xbzrle.c +++ b/migration/xbzrle.c @@ -174,3 +174,127 @@ int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen) return d; } + +#if defined(CONFIG_AVX512BW_OPT) +#pragma GCC push_options +#pragma GCC target("avx512bw") +#include +int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen) +{ + uint32_t zrun_len = 0, nzrun_len = 0; + int d = 0, i = 0, num = 0; + uint8_t *nzrun_start = NULL; + /* add 1 to include residual part in main loop */ + uint32_t count512s = (slen >> 6) + 1; + /* countResidual is tail of data, i.e., countResidual = slen % 64 */ + uint32_t count_residual = slen & 0b111111; + bool never_same = true; + uint64_t mask_residual = 1; + mask_residual <<= count_residual; + mask_residual -= 1; + __m512i r = _mm512_set1_epi32(0); + + while (count512s) { + if (d + 2 > dlen) { + return -1; + } + + int bytes_to_check = 64; + uint64_t mask = 0xffffffffffffffff; + if (count512s == 1) { + bytes_to_check = count_residual; + mask = mask_residual; + } + __m512i old_data = _mm512_mask_loadu_epi8(r, + mask, old_buf + i); + __m512i new_data = _mm512_mask_loadu_epi8(r, + mask, new_buf + i); + uint64_t comp = _mm512_cmpeq_epi8_mask(old_data, new_data); + count512s--; + + bool is_same = (comp & 0x1); + while (bytes_to_check) { + if (is_same) { + if (nzrun_len) { + d += uleb128_encode_small(dst + d, nzrun_len); + if (d + nzrun_len > dlen) { + return -1; + } + nzrun_start = new_buf + i - nzrun_len; + memcpy(dst + d, nzrun_start, nzrun_len); + d += nzrun_len; + nzrun_len = 0; + } + /* 64 data at a time for speed */ + if (count512s && (comp == 0xffffffffffffffff)) { + i += 64; + zrun_len += 64; + break; + } + never_same = false; + num = __builtin_ctzll(~comp); + num = (num < bytes_to_check) ? num : bytes_to_check; + zrun_len += num; + bytes_to_check -= num; + comp >>= num; + i += num; + if (bytes_to_check) { + /* still has different data after same data */ + d += uleb128_encode_small(dst + d, zrun_len); + zrun_len = 0; + } else { + break; + } + } + if (never_same || zrun_len) { + /* + * never_same only acts if + * data begins with diff in first count512s + */ + d += uleb128_encode_small(dst + d, zrun_len); + zrun_len = 0; + never_same = false; + } + /* has diff, 64 data at a time for speed */ + if ((bytes_to_check == 64) && (comp == 0x0)) { + i += 64; + nzrun_len += 64; + break; + } + num = __builtin_ctzll(comp); + num = (num < bytes_to_check) ? num : bytes_to_check; + nzrun_len += num; + bytes_to_check -= num; + comp >>= num; + i += num; + if (bytes_to_check) { + /* mask like 111000 */ + d += uleb128_encode_small(dst + d, nzrun_len); + /* overflow */ + if (d + nzrun_len > dlen) { + return -1; + } + nzrun_start = new_buf + i - nzrun_len; + memcpy(dst + d, nzrun_start, nzrun_len); + d += nzrun_len; + nzrun_len = 0; + is_same = true; + } + } + } + + if (nzrun_len != 0) { + d += uleb128_encode_small(dst + d, nzrun_len); + /* overflow */ + if (d + nzrun_len > dlen) { + return -1; + } + nzrun_start = new_buf + i - nzrun_len; + memcpy(dst + d, nzrun_start, nzrun_len); + d += nzrun_len; + } + return d; +} +#pragma GCC pop_options +#endif diff --git a/migration/xbzrle.h b/migration/xbzrle.h index a0db507b9c..6feb49160a 100644 --- a/migration/xbzrle.h +++ b/migration/xbzrle.h @@ -18,4 +18,8 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, uint8_t *dst, int dlen); int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen); +#if defined(CONFIG_AVX512BW_OPT) +int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen); +#endif #endif diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 0f71e92dcb..c2982ea087 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -70,6 +70,7 @@ meson_options_help() { printf "%s\n" ' attr attr/xattr support' printf "%s\n" ' auth-pam PAM access control' printf "%s\n" ' avx2 AVX2 optimizations' + printf "%s\n" ' avx512bw AVX512BW optimizations' printf "%s\n" ' avx512f AVX512F optimizations' printf "%s\n" ' blkio libblkio block device driver' printf "%s\n" ' bochs bochs image format support' @@ -198,6 +199,8 @@ _meson_option_parse() { --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; --enable-avx2) printf "%s" -Davx2=enabled ;; --disable-avx2) printf "%s" -Davx2=disabled ;; + --enable-avx512bw) printf "%s" -Davx512bw=enabled ;; + --disable-avx512bw) printf "%s" -Davx512bw=disabled ;; --enable-avx512f) printf "%s" -Davx512f=enabled ;; --disable-avx512f) printf "%s" -Davx512f=disabled ;; --enable-gcov) printf "%s" -Db_coverage=true ;; From cc98c9fd5c17b8ab62ad91b183060d8f70b9d00d Mon Sep 17 00:00:00 2001 From: ling xu Date: Wed, 16 Nov 2022 23:29:23 +0800 Subject: [PATCH 686/814] Update bench-code for addressing CI problem Unit test code is in test-xbzrle.c, and benchmark code is in xbzrle-bench.c for performance benchmarking. we have modified xbzrle-bench.c to address CI problem. Signed-off-by: ling xu Co-authored-by: Zhou Zhao Co-authored-by: Jun Jin Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- tests/bench/meson.build | 6 + tests/bench/xbzrle-bench.c | 469 +++++++++++++++++++++++++++++++++++++ tests/unit/test-xbzrle.c | 39 ++- 3 files changed, 509 insertions(+), 5 deletions(-) create mode 100644 tests/bench/xbzrle-bench.c diff --git a/tests/bench/meson.build b/tests/bench/meson.build index 279a8fcc33..7477a1f401 100644 --- a/tests/bench/meson.build +++ b/tests/bench/meson.build @@ -3,6 +3,12 @@ qht_bench = executable('qht-bench', sources: 'qht-bench.c', dependencies: [qemuutil]) +if have_system +xbzrle_bench = executable('xbzrle-bench', + sources: 'xbzrle-bench.c', + dependencies: [qemuutil,migration]) +endif + executable('atomic_add-bench', sources: files('atomic_add-bench.c'), dependencies: [qemuutil], diff --git a/tests/bench/xbzrle-bench.c b/tests/bench/xbzrle-bench.c new file mode 100644 index 0000000000..8848a3a32d --- /dev/null +++ b/tests/bench/xbzrle-bench.c @@ -0,0 +1,469 @@ +/* + * Xor Based Zero Run Length Encoding unit tests. + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Orit Wasserman + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "../migration/xbzrle.h" + +#if defined(CONFIG_AVX512BW_OPT) +#define XBZRLE_PAGE_SIZE 4096 +static bool is_cpu_support_avx512bw; +#include "qemu/cpuid.h" +static void __attribute__((constructor)) init_cpu_flag(void) +{ + unsigned max = __get_cpuid_max(0, NULL); + int a, b, c, d; + is_cpu_support_avx512bw = false; + if (max >= 1) { + __cpuid(1, a, b, c, d); + /* We must check that AVX is not just available, but usable. */ + if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { + int bv; + __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); + __cpuid_count(7, 0, a, b, c, d); + /* 0xe6: + * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 + * and ZMM16-ZMM31 state are enabled by OS) + * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) + */ + if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { + is_cpu_support_avx512bw = true; + } + } + } + return ; +} + +struct ResTime { + float t_raw; + float t_512; +}; + + +/* Function prototypes +int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen); +*/ +static void encode_decode_zero(struct ResTime *res) +{ + uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); + int i = 0; + int dlen = 0, dlen512 = 0; + int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + buffer[1000 + i] = i; + buffer512[1000 + i] = i; + } + + buffer[1000 + diff_len + 3] = 103; + buffer[1000 + diff_len + 5] = 105; + + buffer512[1000 + diff_len + 3] = 103; + buffer512[1000 + diff_len + 5] = 105; + + /* encode zero page */ + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + dlen = xbzrle_encode_buffer(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + g_assert(dlen == 0); + + t_start512 = clock(); + dlen512 = xbzrle_encode_buffer_avx512(buffer512, buffer512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + g_assert(dlen512 == 0); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(buffer); + g_free(compressed); + g_free(buffer512); + g_free(compressed512); + +} + +static void test_encode_decode_zero_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_zero(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("Zero test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} + +static void encode_decode_unchanged(struct ResTime *res) +{ + uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); + int i = 0; + int dlen = 0, dlen512 = 0; + int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + test[1000 + i] = i + 4; + test512[1000 + i] = i + 4; + } + + test[1000 + diff_len + 3] = 107; + test[1000 + diff_len + 5] = 109; + + test512[1000 + diff_len + 3] = 107; + test512[1000 + diff_len + 5] = 109; + + /* test unchanged buffer */ + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + dlen = xbzrle_encode_buffer(test, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + g_assert(dlen == 0); + + t_start512 = clock(); + dlen512 = xbzrle_encode_buffer_avx512(test512, test512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + g_assert(dlen512 == 0); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(test); + g_free(compressed); + g_free(test512); + g_free(compressed512); + +} + +static void test_encode_decode_unchanged_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_unchanged(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("Unchanged test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} + +static void encode_decode_1_byte(struct ResTime *res) +{ + uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); + uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); + int dlen = 0, rc = 0, dlen512 = 0, rc512 = 0; + uint8_t buf[2]; + uint8_t buf512[2]; + + test[XBZRLE_PAGE_SIZE - 1] = 1; + test512[XBZRLE_PAGE_SIZE - 1] = 1; + + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + dlen = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2)); + + rc = xbzrle_decode_buffer(compressed, dlen, buffer, XBZRLE_PAGE_SIZE); + g_assert(rc == XBZRLE_PAGE_SIZE); + g_assert(memcmp(test, buffer, XBZRLE_PAGE_SIZE) == 0); + + t_start512 = clock(); + dlen512 = xbzrle_encode_buffer_avx512(buffer512, test512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + g_assert(dlen512 == (uleb128_encode_small(&buf512[0], 4095) + 2)); + + rc512 = xbzrle_decode_buffer(compressed512, dlen512, buffer512, + XBZRLE_PAGE_SIZE); + g_assert(rc512 == XBZRLE_PAGE_SIZE); + g_assert(memcmp(test512, buffer512, XBZRLE_PAGE_SIZE) == 0); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(buffer); + g_free(compressed); + g_free(test); + g_free(buffer512); + g_free(compressed512); + g_free(test512); + +} + +static void test_encode_decode_1_byte_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_1_byte(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("1 byte test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} + +static void encode_decode_overflow(struct ResTime *res) +{ + uint8_t *compressed = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); + int i = 0, rc = 0, rc512 = 0; + + for (i = 0; i < XBZRLE_PAGE_SIZE / 2 - 1; i++) { + test[i * 2] = 1; + test512[i * 2] = 1; + } + + /* encode overflow */ + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + rc = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + g_assert(rc == -1); + + t_start512 = clock(); + rc512 = xbzrle_encode_buffer_avx512(buffer512, test512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + g_assert(rc512 == -1); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(buffer); + g_free(compressed); + g_free(test); + g_free(buffer512); + g_free(compressed512); + g_free(test512); + +} + +static void test_encode_decode_overflow_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_overflow(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("Overflow test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} + +static void encode_decode_range_avx512(struct ResTime *res) +{ + uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); + uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); + uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); + int i = 0, rc = 0, rc512 = 0; + int dlen = 0, dlen512 = 0; + + int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + buffer[1000 + i] = i; + test[1000 + i] = i + 4; + buffer512[1000 + i] = i; + test512[1000 + i] = i + 4; + } + + buffer[1000 + diff_len + 3] = 103; + test[1000 + diff_len + 3] = 107; + + buffer[1000 + diff_len + 5] = 105; + test[1000 + diff_len + 5] = 109; + + buffer512[1000 + diff_len + 3] = 103; + test512[1000 + diff_len + 3] = 107; + + buffer512[1000 + diff_len + 5] = 105; + test512[1000 + diff_len + 5] = 109; + + /* test encode/decode */ + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); + g_assert(rc < XBZRLE_PAGE_SIZE); + g_assert(memcmp(test, buffer, XBZRLE_PAGE_SIZE) == 0); + + t_start512 = clock(); + dlen512 = xbzrle_encode_buffer_avx512(test512, buffer512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + rc512 = xbzrle_decode_buffer(compressed512, dlen512, test512, XBZRLE_PAGE_SIZE); + g_assert(rc512 < XBZRLE_PAGE_SIZE); + g_assert(memcmp(test512, buffer512, XBZRLE_PAGE_SIZE) == 0); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(buffer); + g_free(compressed); + g_free(test); + g_free(buffer512); + g_free(compressed512); + g_free(test512); + +} + +static void test_encode_decode_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_range_avx512(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("Encode decode test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} + +static void encode_decode_random(struct ResTime *res) +{ + uint8_t *buffer = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed = g_malloc(XBZRLE_PAGE_SIZE); + uint8_t *test = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *buffer512 = g_malloc0(XBZRLE_PAGE_SIZE); + uint8_t *compressed512 = g_malloc(XBZRLE_PAGE_SIZE); + uint8_t *test512 = g_malloc0(XBZRLE_PAGE_SIZE); + int i = 0, rc = 0, rc512 = 0; + int dlen = 0, dlen512 = 0; + + int diff_len = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1); + /* store the index of diff */ + int dirty_index[diff_len]; + for (int j = 0; j < diff_len; j++) { + dirty_index[j] = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE - 1); + } + for (i = diff_len - 1; i >= 0; i--) { + buffer[dirty_index[i]] = i; + test[dirty_index[i]] = i + 4; + buffer512[dirty_index[i]] = i; + test512[dirty_index[i]] = i + 4; + } + + time_t t_start, t_end, t_start512, t_end512; + t_start = clock(); + dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, + XBZRLE_PAGE_SIZE); + t_end = clock(); + float time_val = difftime(t_end, t_start); + rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); + g_assert(rc < XBZRLE_PAGE_SIZE); + + t_start512 = clock(); + dlen512 = xbzrle_encode_buffer_avx512(test512, buffer512, XBZRLE_PAGE_SIZE, + compressed512, XBZRLE_PAGE_SIZE); + t_end512 = clock(); + float time_val512 = difftime(t_end512, t_start512); + rc512 = xbzrle_decode_buffer(compressed512, dlen512, test512, XBZRLE_PAGE_SIZE); + g_assert(rc512 < XBZRLE_PAGE_SIZE); + + res->t_raw = time_val; + res->t_512 = time_val512; + + g_free(buffer); + g_free(compressed); + g_free(test); + g_free(buffer512); + g_free(compressed512); + g_free(test512); + +} + +static void test_encode_decode_random_avx512(void) +{ + int i; + float time_raw = 0.0, time_512 = 0.0; + struct ResTime res; + for (i = 0; i < 10000; i++) { + encode_decode_random(&res); + time_raw += res.t_raw; + time_512 += res.t_512; + } + printf("Random test:\n"); + printf("Raw xbzrle_encode time is %f ms\n", time_raw); + printf("512 xbzrle_encode time is %f ms\n", time_512); +} +#endif + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_rand_int(); + #if defined(CONFIG_AVX512BW_OPT) + if (likely(is_cpu_support_avx512bw)) { + g_test_add_func("/xbzrle/encode_decode_zero", test_encode_decode_zero_avx512); + g_test_add_func("/xbzrle/encode_decode_unchanged", + test_encode_decode_unchanged_avx512); + g_test_add_func("/xbzrle/encode_decode_1_byte", test_encode_decode_1_byte_avx512); + g_test_add_func("/xbzrle/encode_decode_overflow", + test_encode_decode_overflow_avx512); + g_test_add_func("/xbzrle/encode_decode", test_encode_decode_avx512); + g_test_add_func("/xbzrle/encode_decode_random", test_encode_decode_random_avx512); + } + #endif + return g_test_run(); +} diff --git a/tests/unit/test-xbzrle.c b/tests/unit/test-xbzrle.c index ef951b6e54..547046d093 100644 --- a/tests/unit/test-xbzrle.c +++ b/tests/unit/test-xbzrle.c @@ -16,6 +16,35 @@ #define XBZRLE_PAGE_SIZE 4096 +int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int, + uint8_t *, int) = xbzrle_encode_buffer; +#if defined(CONFIG_AVX512BW_OPT) +#include "qemu/cpuid.h" +static void __attribute__((constructor)) init_cpu_flag(void) +{ + unsigned max = __get_cpuid_max(0, NULL); + int a, b, c, d; + if (max >= 1) { + __cpuid(1, a, b, c, d); + /* We must check that AVX is not just available, but usable. */ + if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { + int bv; + __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); + __cpuid_count(7, 0, a, b, c, d); + /* 0xe6: + * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15 + * and ZMM16-ZMM31 state are enabled by OS) + * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS) + */ + if ((bv & 0xe6) == 0xe6 && (b & bit_AVX512BW)) { + xbzrle_encode_buffer_func = xbzrle_encode_buffer_avx512; + } + } + } + return ; +} +#endif + static void test_uleb(void) { uint32_t i, val; @@ -54,7 +83,7 @@ static void test_encode_decode_zero(void) buffer[1000 + diff_len + 5] = 105; /* encode zero page */ - dlen = xbzrle_encode_buffer(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, + dlen = xbzrle_encode_buffer_func(buffer, buffer, XBZRLE_PAGE_SIZE, compressed, XBZRLE_PAGE_SIZE); g_assert(dlen == 0); @@ -78,7 +107,7 @@ static void test_encode_decode_unchanged(void) test[1000 + diff_len + 5] = 109; /* test unchanged buffer */ - dlen = xbzrle_encode_buffer(test, test, XBZRLE_PAGE_SIZE, compressed, + dlen = xbzrle_encode_buffer_func(test, test, XBZRLE_PAGE_SIZE, compressed, XBZRLE_PAGE_SIZE); g_assert(dlen == 0); @@ -96,7 +125,7 @@ static void test_encode_decode_1_byte(void) test[XBZRLE_PAGE_SIZE - 1] = 1; - dlen = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, + dlen = xbzrle_encode_buffer_func(buffer, test, XBZRLE_PAGE_SIZE, compressed, XBZRLE_PAGE_SIZE); g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2)); @@ -121,7 +150,7 @@ static void test_encode_decode_overflow(void) } /* encode overflow */ - rc = xbzrle_encode_buffer(buffer, test, XBZRLE_PAGE_SIZE, compressed, + rc = xbzrle_encode_buffer_func(buffer, test, XBZRLE_PAGE_SIZE, compressed, XBZRLE_PAGE_SIZE); g_assert(rc == -1); @@ -152,7 +181,7 @@ static void encode_decode_range(void) test[1000 + diff_len + 5] = 109; /* test encode/decode */ - dlen = xbzrle_encode_buffer(test, buffer, XBZRLE_PAGE_SIZE, compressed, + dlen = xbzrle_encode_buffer_func(test, buffer, XBZRLE_PAGE_SIZE, compressed, XBZRLE_PAGE_SIZE); rc = xbzrle_decode_buffer(compressed, dlen, test, XBZRLE_PAGE_SIZE); From d6f74fd12e464325f260d157c221e29480c62368 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 8 Feb 2023 15:28:10 -0500 Subject: [PATCH 687/814] migration: Rework multi-channel checks on URI The whole idea of multi-channel checks was not properly done, IMHO. Currently we check multi-channel in a lot of places, but actually that's not needed because we only need to check it right after we get the URI and that should be it. If the URI check succeeded, we should never need to check it again because we must have it. If it check fails, we should fail immediately on either the qmp_migrate or qmp_migrate_incoming, instead of failingg it later after the connection established. Neither should we fail any set capabiliities like what we used to do here: 5ad15e8614 ("migration: allow enabling mutilfd for specific protocol only", 2021-10-19) Because logically the URI will only be set later after the capability is set, so it doesn't make a lot of sense to check the URI type when setting the capability, because we're checking the cap with an old URI passed in, and that may not even be the URI we're going to use later. This patch mostly reverted all such checks for before, dropping the variable migrate_allow_multi_channels and helpers. Instead, add a common helper to check URI for multi-channels for either qmp_migrate and qmp_migrate_incoming and that should do all the proper checks. The failure will only trigger with the "migrate" or "migrate_incoming" command, or when user specified "-incoming xxx" where "xxx" is not "defer". Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 51 +++++++++++++++++++++------------------- migration/migration.h | 3 --- migration/multifd.c | 12 ++-------- migration/postcopy-ram.c | 6 ----- 4 files changed, 29 insertions(+), 43 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 7a14aa98d8..f242d657e8 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -184,16 +184,27 @@ static int migration_maybe_pause(MigrationState *s, int new_state); static void migrate_fd_cancel(MigrationState *s); -static bool migrate_allow_multi_channels = true; - -void migrate_protocol_allow_multi_channels(bool allow) +static bool migration_needs_multiple_sockets(void) { - migrate_allow_multi_channels = allow; + return migrate_use_multifd() || migrate_postcopy_preempt(); } -bool migrate_multi_channels_is_allowed(void) +static bool uri_supports_multi_channels(const char *uri) { - return migrate_allow_multi_channels; + return strstart(uri, "tcp:", NULL) || strstart(uri, "unix:", NULL) || + strstart(uri, "vsock:", NULL); +} + +static bool +migration_channels_and_uri_compatible(const char *uri, Error **errp) +{ + if (migration_needs_multiple_sockets() && + !uri_supports_multi_channels(uri)) { + error_setg(errp, "Migration requires multi-channel URIs (e.g. tcp)"); + return false; + } + + return true; } static gint page_request_addr_cmp(gconstpointer ap, gconstpointer bp) @@ -493,12 +504,15 @@ static void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p = NULL; - migrate_protocol_allow_multi_channels(false); /* reset it anyway */ + /* URI is not suitable for migration? */ + if (!migration_channels_and_uri_compatible(uri, errp)) { + return; + } + qapi_event_send_migration(MIGRATION_STATUS_SETUP); if (strstart(uri, "tcp:", &p) || strstart(uri, "unix:", NULL) || strstart(uri, "vsock:", NULL)) { - migrate_protocol_allow_multi_channels(true); socket_start_incoming_migration(p ? p : uri, errp); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { @@ -723,11 +737,6 @@ void migration_fd_process_incoming(QEMUFile *f, Error **errp) migration_incoming_process(); } -static bool migration_needs_multiple_sockets(void) -{ - return migrate_use_multifd() || migrate_postcopy_preempt(); -} - void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); @@ -1378,15 +1387,6 @@ static bool migrate_caps_check(bool *cap_list, } #endif - - /* incoming side only */ - if (runstate_check(RUN_STATE_INMIGRATE) && - !migrate_multi_channels_is_allowed() && - cap_list[MIGRATION_CAPABILITY_MULTIFD]) { - error_setg(errp, "multifd is not supported by current protocol"); - return false; - } - if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) { if (!cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { error_setg(errp, "Postcopy preempt requires postcopy-ram"); @@ -2471,6 +2471,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, MigrationState *s = migrate_get_current(); const char *p = NULL; + /* URI is not suitable for migration? */ + if (!migration_channels_and_uri_compatible(uri, errp)) { + return; + } + if (!migrate_prepare(s, has_blk && blk, has_inc && inc, has_resume && resume, errp)) { /* Error detected, put into errp */ @@ -2483,11 +2488,9 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, } } - migrate_protocol_allow_multi_channels(false); if (strstart(uri, "tcp:", &p) || strstart(uri, "unix:", NULL) || strstart(uri, "vsock:", NULL)) { - migrate_protocol_allow_multi_channels(true); socket_start_outgoing_migration(s, p ? p : uri, &local_err); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { diff --git a/migration/migration.h b/migration/migration.h index 66511ce532..c351872360 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -474,7 +474,4 @@ void migration_cancel(const Error *error); void populate_vfio_info(MigrationInfo *info); void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page); -bool migrate_multi_channels_is_allowed(void); -void migrate_protocol_allow_multi_channels(bool allow); - #endif diff --git a/migration/multifd.c b/migration/multifd.c index 7aa030fb19..99a59830c8 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -516,7 +516,7 @@ void multifd_save_cleanup(void) { int i; - if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { + if (!migrate_use_multifd()) { return; } multifd_send_terminate_threads(NULL); @@ -913,10 +913,6 @@ int multifd_save_setup(Error **errp) if (!migrate_use_multifd()) { return 0; } - if (!migrate_multi_channels_is_allowed()) { - error_setg(errp, "multifd is not supported by current protocol"); - return -1; - } thread_count = migrate_multifd_channels(); multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); @@ -1021,7 +1017,7 @@ int multifd_load_cleanup(Error **errp) { int i; - if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) { + if (!migrate_use_multifd()) { return 0; } multifd_recv_terminate_threads(NULL); @@ -1172,10 +1168,6 @@ int multifd_load_setup(Error **errp) return 0; } - if (!migrate_multi_channels_is_allowed()) { - error_setg(errp, "multifd is not supported by current protocol"); - return -1; - } thread_count = migrate_multifd_channels(); multifd_recv_state = g_malloc0(sizeof(*multifd_recv_state)); multifd_recv_state->params = g_new0(MultiFDRecvParams, thread_count); diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 53299b7a5e..9a9d0ecf49 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1635,12 +1635,6 @@ int postcopy_preempt_setup(MigrationState *s, Error **errp) return 0; } - if (!migrate_multi_channels_is_allowed()) { - error_setg(errp, "Postcopy preempt is not supported as current " - "migration stream does not support multi-channels."); - return -1; - } - /* Kick an async task to connect */ socket_send_channel_create(postcopy_preempt_send_channel_new, s); From fc063a7b8ac0e1362897f4fb3f5c09dce2b2f5af Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 8 Feb 2023 15:28:11 -0500 Subject: [PATCH 688/814] migration: Cleanup postcopy_preempt_setup() Since we just dropped the only case where postcopy_preempt_setup() can return an error, it doesn't need a retval anymore because it never fails. Move the preempt check to the caller, preparing it to be used elsewhere to do nothing but as simple as kicking the async connection. Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 8 ++------ migration/postcopy-ram.c | 8 +------- migration/postcopy-ram.h | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index f242d657e8..fb0ecf5649 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -4347,12 +4347,8 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) } /* This needs to be done before resuming a postcopy */ - if (postcopy_preempt_setup(s, &local_err)) { - error_report_err(local_err); - migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, - MIGRATION_STATUS_FAILED); - migrate_fd_cleanup(s); - return; + if (migrate_postcopy_preempt()) { + postcopy_preempt_setup(s); } if (resume) { diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 9a9d0ecf49..de6d4a3fd4 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1629,16 +1629,10 @@ int postcopy_preempt_wait_channel(MigrationState *s) return s->postcopy_qemufile_src ? 0 : -1; } -int postcopy_preempt_setup(MigrationState *s, Error **errp) +void postcopy_preempt_setup(MigrationState *s) { - if (!migrate_postcopy_preempt()) { - return 0; - } - /* Kick an async task to connect */ socket_send_channel_create(postcopy_preempt_send_channel_new, s); - - return 0; } static void postcopy_pause_ram_fast_load(MigrationIncomingState *mis) diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index 25881c4127..d5604cbcf1 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -191,7 +191,7 @@ enum PostcopyChannels { }; void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); -int postcopy_preempt_setup(MigrationState *s, Error **errp); +void postcopy_preempt_setup(MigrationState *s); int postcopy_preempt_wait_channel(MigrationState *s); #endif From b28fb58227aa88b940fd45b31b0f66c8e3b8cdc0 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 8 Feb 2023 15:28:12 -0500 Subject: [PATCH 689/814] migration: Add a semaphore to count PONGs This is mostly useless, but useful for us to know whether the main channel is correctly established without changing the migration protocol. Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 3 +++ migration/migration.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index fb0ecf5649..a2e362541d 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3025,6 +3025,7 @@ retry: case MIG_RP_MSG_PONG: tmp32 = ldl_be_p(buf); trace_source_return_path_thread_pong(tmp32); + qemu_sem_post(&ms->rp_state.rp_pong_acks); break; case MIG_RP_MSG_REQ_PAGES: @@ -4524,6 +4525,7 @@ static void migration_instance_finalize(Object *obj) qemu_sem_destroy(&ms->postcopy_pause_sem); qemu_sem_destroy(&ms->postcopy_pause_rp_sem); qemu_sem_destroy(&ms->rp_state.rp_sem); + qemu_sem_destroy(&ms->rp_state.rp_pong_acks); qemu_sem_destroy(&ms->postcopy_qemufile_src_sem); error_free(ms->error); } @@ -4570,6 +4572,7 @@ static void migration_instance_init(Object *obj) qemu_sem_init(&ms->postcopy_pause_sem, 0); qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); qemu_sem_init(&ms->rp_state.rp_sem, 0); + qemu_sem_init(&ms->rp_state.rp_pong_acks, 0); qemu_sem_init(&ms->rate_limit_sem, 0); qemu_sem_init(&ms->wait_unplug_sem, 0); qemu_sem_init(&ms->postcopy_qemufile_src_sem, 0); diff --git a/migration/migration.h b/migration/migration.h index c351872360..4cb1cb6fa8 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -276,6 +276,12 @@ struct MigrationState { */ bool rp_thread_created; QemuSemaphore rp_sem; + /* + * We post to this when we got one PONG from dest. So far it's an + * easy way to know the main channel has successfully established + * on dest QEMU. + */ + QemuSemaphore rp_pong_acks; } rp_state; double mbps; From 5655aab0794b5c82e61683cab215c5f745be8af3 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 8 Feb 2023 15:28:13 -0500 Subject: [PATCH 690/814] migration: Postpone postcopy preempt channel to be after main Postcopy with preempt-mode enabled needs two channels to communicate. The order of channel establishment is not guaranteed. It can happen that the dest QEMU got the preempt channel connection request before the main channel is established, then the migration may make no progress even during precopy due to the wrong order. To fix it, create the preempt channel only if we know the main channel is established. For a general postcopy migration, we delay it until postcopy_start(), that's where we already went through some part of precopy on the main channel. To make sure dest QEMU has already established the channel, we wait until we got the first PONG received. That's something we do at the start of precopy when postcopy enabled so it's guaranteed to happen sooner or later. For a postcopy recovery, we delay it to qemu_savevm_state_resume_prepare() where we'll have round trips of data on bitmap synchronizations, which means the main channel must have been established. Signed-off-by: Peter Xu Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 72 ++++++++++++++++++++++++++++++---------- migration/migration.h | 6 ++++ migration/postcopy-ram.c | 17 ++++++++-- migration/postcopy-ram.h | 2 +- migration/savevm.c | 6 +++- 5 files changed, 82 insertions(+), 21 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index a2e362541d..a5c22e327d 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -235,6 +235,8 @@ void migration_object_init(void) qemu_sem_init(¤t_incoming->postcopy_pause_sem_dst, 0); qemu_sem_init(¤t_incoming->postcopy_pause_sem_fault, 0); qemu_sem_init(¤t_incoming->postcopy_pause_sem_fast_load, 0); + qemu_sem_init(¤t_incoming->postcopy_qemufile_dst_done, 0); + qemu_mutex_init(¤t_incoming->page_request_mutex); current_incoming->page_requested = g_tree_new(page_request_addr_cmp); @@ -737,6 +739,31 @@ void migration_fd_process_incoming(QEMUFile *f, Error **errp) 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) +{ + /* Multifd doesn't start unless all channels are established */ + if (migrate_use_multifd()) { + return migration_has_all_channels(); + } + + /* Preempt channel only starts when the main channel is created */ + if (migrate_postcopy_preempt()) { + return main_channel; + } + + /* + * 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); + return true; +} + void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); @@ -798,7 +825,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) } } - if (migration_has_all_channels()) { + if (migration_should_start_incoming(default_channel)) { /* If it's a recovery, we're done */ if (postcopy_try_recover()) { return; @@ -3159,6 +3186,13 @@ static int await_return_path_close_on_source(MigrationState *ms) return ms->rp_state.error; } +static inline void +migration_wait_main_channel(MigrationState *ms) +{ + /* Wait until one PONG message received */ + qemu_sem_wait(&ms->rp_state.rp_pong_acks); +} + /* * Switch from normal iteration to postcopy * Returns non-0 on error @@ -3173,9 +3207,12 @@ static int postcopy_start(MigrationState *ms) bool restart_block = false; int cur_state = MIGRATION_STATUS_ACTIVE; - if (postcopy_preempt_wait_channel(ms)) { - migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED); - return -1; + if (migrate_postcopy_preempt()) { + migration_wait_main_channel(ms); + if (postcopy_preempt_establish_channel(ms)) { + migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED); + return -1; + } } if (!migrate_pause_before_switchover()) { @@ -3586,6 +3623,20 @@ static int postcopy_do_resume(MigrationState *s) return ret; } + /* + * If preempt is enabled, re-establish the preempt channel. Note that + * we do it after resume prepare to make sure the main channel will be + * created before the preempt channel. E.g. with weak network, the + * dest QEMU may get messed up with the preempt and main channels on + * the order of connection setup. This guarantees the correct order. + */ + ret = postcopy_preempt_establish_channel(s); + if (ret) { + error_report("%s: postcopy_preempt_establish_channel(): %d", + __func__, ret); + return ret; + } + /* * Last handshake with destination on the resume (destination will * switch to postcopy-active afterwards) @@ -3647,14 +3698,6 @@ static MigThrError postcopy_pause(MigrationState *s) if (s->state == MIGRATION_STATUS_POSTCOPY_RECOVER) { /* Woken up by a recover procedure. Give it a shot */ - if (postcopy_preempt_wait_channel(s)) { - /* - * Preempt enabled, and new channel create failed; loop - * back to wait for another recovery. - */ - continue; - } - /* * Firstly, let's wake up the return path now, with a new * return path channel. @@ -4347,11 +4390,6 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) } } - /* This needs to be done before resuming a postcopy */ - if (migrate_postcopy_preempt()) { - postcopy_preempt_setup(s); - } - if (resume) { /* Wakeup the main migration thread to do the recovery */ migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED, diff --git a/migration/migration.h b/migration/migration.h index 4cb1cb6fa8..2da2f8a164 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -116,6 +116,12 @@ struct MigrationIncomingState { unsigned int postcopy_channels; /* QEMUFile for postcopy only; it'll be handled by a separate thread */ QEMUFile *postcopy_qemufile_dst; + /* + * When postcopy_qemufile_dst is properly setup, this sem is posted. + * One can wait on this semaphore to wait until the preempt channel is + * properly setup. + */ + QemuSemaphore postcopy_qemufile_dst_done; /* Postcopy priority thread is used to receive postcopy requested pages */ QemuThread postcopy_prio_thread; bool postcopy_prio_thread_created; diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index de6d4a3fd4..f54f44d899 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1197,6 +1197,11 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis) } if (migrate_postcopy_preempt()) { + /* + * The preempt channel is established in asynchronous way. Wait + * for its completion. + */ + qemu_sem_wait(&mis->postcopy_qemufile_dst_done); /* * This thread needs to be created after the temp pages because * it'll fetch RAM_CHANNEL_POSTCOPY PostcopyTmpPage immediately. @@ -1544,6 +1549,7 @@ void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file) */ qemu_file_set_blocking(file, true); mis->postcopy_qemufile_dst = file; + qemu_sem_post(&mis->postcopy_qemufile_dst_done); trace_postcopy_preempt_new_channel(); } @@ -1612,14 +1618,21 @@ out: postcopy_preempt_send_channel_done(s, ioc, local_err); } -/* Returns 0 if channel established, -1 for error. */ -int postcopy_preempt_wait_channel(MigrationState *s) +/* + * This function will kick off an async task to establish the preempt + * channel, and wait until the connection setup completed. Returns 0 if + * channel established, -1 for error. + */ +int postcopy_preempt_establish_channel(MigrationState *s) { /* If preempt not enabled, no need to wait */ if (!migrate_postcopy_preempt()) { return 0; } + /* Kick off async task to establish preempt channel */ + postcopy_preempt_setup(s); + /* * We need the postcopy preempt channel to be established before * starting doing anything. diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index d5604cbcf1..b4867a32d5 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -192,6 +192,6 @@ enum PostcopyChannels { void postcopy_preempt_new_channel(MigrationIncomingState *mis, QEMUFile *file); void postcopy_preempt_setup(MigrationState *s); -int postcopy_preempt_wait_channel(MigrationState *s); +int postcopy_preempt_establish_channel(MigrationState *s); #endif diff --git a/migration/savevm.c b/migration/savevm.c index ce181e21e1..b5e6962bb6 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2200,7 +2200,11 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis) qemu_sem_post(&mis->postcopy_pause_sem_fault); if (migrate_postcopy_preempt()) { - /* The channel should already be setup again; make sure of it */ + /* + * The preempt channel will be created in async manner, now let's + * wait for it and make sure it's created. + */ + qemu_sem_wait(&mis->postcopy_qemufile_dst_done); assert(mis->postcopy_qemufile_dst); /* Kick the fast ram load thread too */ qemu_sem_post(&mis->postcopy_pause_sem_fast_load); From e5bac1f525472d6042a4cdba31dda5825cde0086 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 10 Feb 2023 03:36:28 -0300 Subject: [PATCH 691/814] migration/multifd: Change multifd_load_cleanup() signature and usage Since it's introduction in commit f986c3d256 ("migration: Create multifd migration threads"), multifd_load_cleanup() never returned any value different than 0, neither set up any error on errp. Even though, on process_incoming_migration_bh() an if clause uses it's return value to decide on setting autostart = false, which will never happen. In order to simplify the codebase, change multifd_load_cleanup() signature to 'void multifd_load_cleanup(void)', and for every usage remove error handling or decision made based on return value != 0. Fixes: b5eea99ec2 ("migration: Add yank feature") Reported-by: Li Xiaohui Signed-off-by: Leonardo Bras Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Signed-off-by: Juan Quintela --- migration/migration.c | 14 ++++---------- migration/multifd.c | 6 ++---- migration/multifd.h | 2 +- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index a5c22e327d..5bf332fdd2 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -559,13 +559,7 @@ static void process_incoming_migration_bh(void *opaque) */ qemu_announce_self(&mis->announce_timer, migrate_announce_params()); - if (multifd_load_cleanup(&local_err) != 0) { - error_report_err(local_err); - autostart = false; - } - /* If global state section was not received or we are in running - state, we need to obey autostart. Any other state is set with - runstate_set. */ + multifd_load_cleanup(); dirty_bitmap_mig_before_vm_start(); @@ -665,9 +659,9 @@ fail: migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_FAILED); qemu_fclose(mis->from_src_file); - if (multifd_load_cleanup(&local_err) != 0) { - error_report_err(local_err); - } + + multifd_load_cleanup(); + exit(EXIT_FAILURE); } diff --git a/migration/multifd.c b/migration/multifd.c index 99a59830c8..cac8496edc 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1013,12 +1013,12 @@ static void multifd_recv_terminate_threads(Error *err) } } -int multifd_load_cleanup(Error **errp) +void multifd_load_cleanup(void) { int i; if (!migrate_use_multifd()) { - return 0; + return; } multifd_recv_terminate_threads(NULL); for (i = 0; i < migrate_multifd_channels(); i++) { @@ -1058,8 +1058,6 @@ int multifd_load_cleanup(Error **errp) multifd_recv_state->params = NULL; g_free(multifd_recv_state); multifd_recv_state = NULL; - - return 0; } void multifd_recv_sync_main(void) diff --git a/migration/multifd.h b/migration/multifd.h index ff3aa2e2e9..9a7e1a8826 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -16,7 +16,7 @@ int multifd_save_setup(Error **errp); void multifd_save_cleanup(void); int multifd_load_setup(Error **errp); -int multifd_load_cleanup(Error **errp); +void multifd_load_cleanup(void); bool multifd_recv_all_channels_created(void); void multifd_recv_new_channel(QIOChannel *ioc, Error **errp); void multifd_recv_sync_main(void); From d926f3bb2a84fdb746678629279a143f568c3c86 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 10 Feb 2023 03:36:29 -0300 Subject: [PATCH 692/814] migration/multifd: Remove unnecessary assignment on multifd_load_cleanup() Before assigning "p->quit = true" for every multifd channel, multifd_load_cleanup() will call multifd_recv_terminate_threads() which already does the same assignment, while protected by a mutex. So there is no point doing the same assignment again. Fixes: b5eea99ec2 ("migration: Add yank feature") Reported-by: Li Xiaohui Signed-off-by: Leonardo Bras Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Signed-off-by: Juan Quintela --- migration/multifd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/migration/multifd.c b/migration/multifd.c index cac8496edc..3dd569d0c9 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1025,7 +1025,6 @@ void multifd_load_cleanup(void) MultiFDRecvParams *p = &multifd_recv_state->params[i]; if (p->running) { - p->quit = true; /* * multifd_recv_thread may hung at MULTIFD_FLAG_SYNC handle code, * however try to wakeup it without harm in cleanup phase. From 10351fbad1ee1c1827073c8b2bd644fc897c8ceb Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 10 Feb 2023 03:36:30 -0300 Subject: [PATCH 693/814] migration/multifd: Join all multifd threads in order to avoid leaks Current approach will only join threads that are still running. For the threads not joined, resources or private memory are always kept in the process space and never reclaimed before process end, and this risks serious memory leaks. This should usually not represent a big problem, since multifd migration is usually just ran at most a few times, and after it succeeds there is not much to be done before exiting the process. Yet still, it should not hurt performance to join all of them. Fixes: b5eea99ec2 ("migration: Add yank feature") Reported-by: Li Xiaohui Signed-off-by: Leonardo Bras Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Signed-off-by: Juan Quintela --- migration/multifd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migration/multifd.c b/migration/multifd.c index 3dd569d0c9..840d5814e4 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1030,8 +1030,9 @@ void multifd_load_cleanup(void) * however try to wakeup it without harm in cleanup phase. */ qemu_sem_post(&p->sem_sync); - qemu_thread_join(&p->thread); } + + qemu_thread_join(&p->thread); } for (i = 0; i < migrate_multifd_channels(); i++) { MultiFDRecvParams *p = &multifd_recv_state->params[i]; From cfc3bcf373218fb8757b0ff1ce2017b9b6ad4bff Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Fri, 10 Feb 2023 03:36:31 -0300 Subject: [PATCH 694/814] migration/multifd: Move load_cleanup inside incoming_state_destroy Currently running migration_incoming_state_destroy() without first running multifd_load_cleanup() will cause a yank error: qemu-system-x86_64: ../util/yank.c:107: yank_unregister_instance: Assertion `QLIST_EMPTY(&entry->yankfns)' failed. (core dumped) The above error happens in the target host, when multifd is being used for precopy, and then postcopy is triggered and the migration finishes. This will crash the VM in the target host. To avoid that, move multifd_load_cleanup() inside migration_incoming_state_destroy(), so that the load cleanup becomes part of the incoming state destroying process. Running multifd_load_cleanup() twice can become an issue, though, but the only scenario it could be ran twice is on process_incoming_migration_bh(). So removing this extra call is necessary. On the other hand, this multifd_load_cleanup() call happens way before the migration_incoming_state_destroy() and having this happening before dirty_bitmap_mig_before_vm_start() and vm_start() may be a need. So introduce a new function multifd_load_shutdown() that will mainly stop all multifd threads and close their QIOChannels. Then use this function instead of multifd_load_cleanup() to make sure nothing else is received before dirty_bitmap_mig_before_vm_start(). Fixes: b5eea99ec2 ("migration: Add yank feature") Reported-by: Li Xiaohui Signed-off-by: Leonardo Bras Reviewed-by: Juan Quintela Reviewed-by: Peter Xu Signed-off-by: Juan Quintela --- migration/migration.c | 4 +++- migration/multifd.c | 7 +++++++ migration/multifd.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/migration/migration.c b/migration/migration.c index 5bf332fdd2..90fca70cb7 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -315,6 +315,8 @@ void migration_incoming_state_destroy(void) { struct MigrationIncomingState *mis = migration_incoming_get_current(); + multifd_load_cleanup(); + if (mis->to_src_file) { /* Tell source that we are done */ migrate_send_rp_shut(mis, qemu_file_get_error(mis->from_src_file) != 0); @@ -559,7 +561,7 @@ static void process_incoming_migration_bh(void *opaque) */ qemu_announce_self(&mis->announce_timer, migrate_announce_params()); - multifd_load_cleanup(); + multifd_load_shutdown(); dirty_bitmap_mig_before_vm_start(); diff --git a/migration/multifd.c b/migration/multifd.c index 840d5814e4..5e85c3ea9b 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1013,6 +1013,13 @@ static void multifd_recv_terminate_threads(Error *err) } } +void multifd_load_shutdown(void) +{ + if (migrate_use_multifd()) { + multifd_recv_terminate_threads(NULL); + } +} + void multifd_load_cleanup(void) { int i; diff --git a/migration/multifd.h b/migration/multifd.h index 9a7e1a8826..7cfc265148 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -17,6 +17,7 @@ int multifd_save_setup(Error **errp); void multifd_save_cleanup(void); int multifd_load_setup(Error **errp); void multifd_load_cleanup(void); +void multifd_load_shutdown(void); bool multifd_recv_all_channels_created(void); void multifd_recv_new_channel(QIOChannel *ioc, Error **errp); void multifd_recv_sync_main(void); From 7b548761e5d084f2fc0fc4badebab227b51a8a84 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 28 Jul 2022 10:14:42 +0200 Subject: [PATCH 695/814] ram: Document migration ram flags 0x80 is RAM_SAVE_FLAG_HOOK, it is in qemu-file now. Bigger usable flag is 0x200, noticing that. We can reuse RAM_SAVe_FLAG_FULL. Reviewed-by: Eric Blake Signed-off-by: Juan Quintela --- migration/ram.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 18ac68b181..521912385d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -67,21 +67,25 @@ /***********************************************************/ /* ram save/restore */ -/* RAM_SAVE_FLAG_ZERO used to be named RAM_SAVE_FLAG_COMPRESS, it - * worked for pages that where filled with the same char. We switched +/* + * RAM_SAVE_FLAG_ZERO used to be named RAM_SAVE_FLAG_COMPRESS, it + * worked for pages that were filled with the same char. We switched * it to only search for the zero value. And to avoid confusion with - * RAM_SSAVE_FLAG_COMPRESS_PAGE just rename it. + * RAM_SAVE_FLAG_COMPRESS_PAGE just rename it. */ - -#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */ +/* + * RAM_SAVE_FLAG_FULL was obsoleted in 2009, it can be reused now + */ +#define RAM_SAVE_FLAG_FULL 0x01 #define RAM_SAVE_FLAG_ZERO 0x02 #define RAM_SAVE_FLAG_MEM_SIZE 0x04 #define RAM_SAVE_FLAG_PAGE 0x08 #define RAM_SAVE_FLAG_EOS 0x10 #define RAM_SAVE_FLAG_CONTINUE 0x20 #define RAM_SAVE_FLAG_XBZRLE 0x40 -/* 0x80 is reserved in migration.h start with 0x100 next */ +/* 0x80 is reserved in qemu-file.h for RAM_SAVE_FLAG_HOOK */ #define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100 +/* We can't use any flag that is bigger than 0x200 */ int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int, uint8_t *, int) = xbzrle_encode_buffer; From 74a1b256d775591e57d0c6866a846172241c14a5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 31 Jan 2023 19:02:39 +0100 Subject: [PATCH 696/814] configure: Bump minimum Clang version to 10.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anthony Perard recently reported some problems with Clang v6.0 from Ubuntu Bionic (with regards to the -Wmissing-braces configure test). Since we're not officially supporting that version of Ubuntu anymore, we should better bump our minimum version check in the configure script instead of using our time to fix problems of unsupported compilers. According to repology.org, our supported distros ship these versions of Clang (looking at the highest version only): Fedora 36: 14.0.5 CentOS 8 (RHEL-8): 12.0.1 Debian 11: 13.0.1 OpenSUSE Leap 15.4: 13.0.1 Ubuntu LTS 20.04: 12.0.0 FreeBSD Ports: 15.0.7 NetBSD pkgsrc: 15.0.7 Homebrew: 15.0.7 MSYS2 mingw: 15.0.7 Haiku ports: 12.0.1 While it seems like we could update to v12.0.0 from that point of view, the default version on Ubuntu 20.04 is still v10.0, and we use that for our CI tests based via the tests/docker/dockerfiles/ubuntu2004.docker file. Thus let's make v10.0 our minimum version now (which corresponds to Apple Clang version v12.0). The -Wmissing-braces check can then be removed, too, since both our minimum GCC and our minimum Clang version now handle this correctly. Message-Id: <20230131180239.1582302-1-thuth@redhat.com> Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- configure | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 64960c6000..00415f0b48 100755 --- a/configure +++ b/configure @@ -1018,7 +1018,7 @@ cat << EOF debug-tcg TCG debugging (default is disabled) debug-info debugging information safe-stack SafeStack Stack Smash Protection. Depends on - clang/llvm >= 3.7 and requires coroutine backend ucontext. + clang/llvm and requires coroutine backend ucontext. NOTE: The object files are built at the place where configure is launched EOF @@ -1138,12 +1138,12 @@ fi cat > $TMPC << EOF #if defined(__clang_major__) && defined(__clang_minor__) # ifdef __apple_build_version__ -# if __clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 0) -# error You need at least XCode Clang v10.0 to compile QEMU +# if __clang_major__ < 12 || (__clang_major__ == 12 && __clang_minor__ < 0) +# error You need at least XCode Clang v12.0 to compile QEMU # endif # else -# if __clang_major__ < 6 || (__clang_major__ == 6 && __clang_minor__ < 0) -# error You need at least Clang v6.0 to compile QEMU +# if __clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 0) +# error You need at least Clang v10.0 to compile QEMU # endif # endif #elif defined(__GNUC__) && defined(__GNUC_MINOR__) @@ -1156,7 +1156,7 @@ cat > $TMPC << EOF int main (void) { return 0; } EOF if ! compile_prog "" "" ; then - error_exit "You need at least GCC v7.4 or Clang v6.0 (or XCode Clang v10.0)" + error_exit "You need at least GCC v7.4 or Clang v10.0 (or XCode Clang v12.0)" fi # Accumulate -Wfoo and -Wno-bar separately. @@ -1261,19 +1261,6 @@ EOF fi fi -# Disable -Wmissing-braces on older compilers that warn even for -# the "universal" C zero initializer {0}. -cat > $TMPC << EOF -struct { - int a[2]; -} x = {0}; -EOF -if compile_object "-Werror" "" ; then - : -else - QEMU_CFLAGS="$QEMU_CFLAGS -Wno-missing-braces" -fi - # Our module code doesn't support Windows if test "$modules" = "yes" && test "$mingw32" = "yes" ; then error_exit "Modules are not available for Windows" From bc71d58fd7f149081f89fb3a414ceb79691049db Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Fri, 10 Feb 2023 01:52:07 +0100 Subject: [PATCH 697/814] meson: Add missing libdw knobs Add the missing meson infrastructure bits for the new libdw dependency. Model them after the existing capstone knobs. Fixes: 7c10cb38ccb8 ("accel/tcg: Add debuginfo support") Reported-by: Thomas Huth Signed-off-by: Ilya Leoshkevich Reviewed-by: Thomas Huth Message-Id: <20230210005208.438142-1-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- meson.build | 11 +++++++---- meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index c626ccfa82..50eb670511 100644 --- a/meson.build +++ b/meson.build @@ -1649,10 +1649,13 @@ if libbpf.found() and not cc.links(''' endif # libdw -libdw = dependency('libdw', - method: 'pkg-config', - kwargs: static_kwargs, - required: false) +libdw = not_found +if not get_option('libdw').auto() or have_system or have_user + libdw = dependency('libdw', + method: 'pkg-config', + kwargs: static_kwargs, + required: get_option('libdw')) +endif ################# # config-host.h # diff --git a/meson_options.txt b/meson_options.txt index e5f199119e..56415c5c23 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -131,6 +131,8 @@ option('gio', type : 'feature', value : 'auto', description: 'use libgio for D-Bus support') option('glusterfs', type : 'feature', value : 'auto', description: 'Glusterfs block device driver') +option('libdw', type : 'feature', value : 'auto', + description: 'debuginfo support') option('libiscsi', type : 'feature', value : 'auto', description: 'libiscsi userspace initiator') option('libnfs', type : 'feature', value : 'auto', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index c2982ea087..180c11665a 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -109,6 +109,7 @@ meson_options_help() { printf "%s\n" ' kvm KVM acceleration support' printf "%s\n" ' l2tpv3 l2tpv3 network backend support' printf "%s\n" ' libdaxctl libdaxctl support' + printf "%s\n" ' libdw debuginfo support' printf "%s\n" ' libiscsi libiscsi userspace initiator' printf "%s\n" ' libnfs libnfs block device driver' printf "%s\n" ' libpmem libpmem support' @@ -312,6 +313,8 @@ _meson_option_parse() { --enable-libdaxctl) printf "%s" -Dlibdaxctl=enabled ;; --disable-libdaxctl) printf "%s" -Dlibdaxctl=disabled ;; --libdir=*) quote_sh "-Dlibdir=$2" ;; + --enable-libdw) printf "%s" -Dlibdw=enabled ;; + --disable-libdw) printf "%s" -Dlibdw=disabled ;; --libexecdir=*) quote_sh "-Dlibexecdir=$2" ;; --enable-libiscsi) printf "%s" -Dlibiscsi=enabled ;; --disable-libiscsi) printf "%s" -Dlibiscsi=disabled ;; From 550c6d97ded04f5dc2da7b34d7a95284271304a5 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Fri, 10 Feb 2023 01:52:08 +0100 Subject: [PATCH 698/814] meson: Disable libdw for static builds by default Static QEMU build fails on Debian Bullseye: /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libdw.a(debuginfod-client.o): in function `__libdwfl_debuginfod_init': (.text.startup+0x17): undefined reference to `dlopen' The reason is that pkg-config does not suggest -ldl for libdw, and adding --extra-ldflags="-ldl" resolves the issue. However, static linking with libdw is an unclear topic: * Linux perf does it. * Debian's libdw-dev description says: Only link to the static version for special cases and when you don't need anything from the ebl backends. * As the error message above indicates, -ldl is also needed for debuginfod support. The functionality provided by libdw is needed for analyzing performance of JITed code, which is mostly useful to developers and researchers. Therefore, in order to avoid unpleasant surprises for people who don't need this, simply disable libdw for static builds by default. It can still be enabled explicitly if needed. Reported-by: John Paul Adrian Glaubitz Signed-off-by: Ilya Leoshkevich Message-Id: <20230210005208.438142-2-iii@linux.ibm.com> Signed-off-by: Thomas Huth --- meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 50eb670511..0026bba0ce 100644 --- a/meson.build +++ b/meson.build @@ -1650,7 +1650,8 @@ endif # libdw libdw = not_found -if not get_option('libdw').auto() or have_system or have_user +if not get_option('libdw').auto() or \ + (not enable_static and (have_system or have_user)) libdw = dependency('libdw', method: 'pkg-config', kwargs: static_kwargs, From bb9ecae70bbd1ab1daf94d893b02c78dfe1314f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 31 Jan 2023 09:42:23 +0000 Subject: [PATCH 699/814] build: deprecate --enable-gprof builds and remove from CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As gprof relies on instrumentation you rarely get useful data compared to a real optimised build. Lets deprecate the build option and simplify the CI configuration as a result. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1338 Signed-off-by: Alex Bennée Message-Id: <20230131094224.861621-1-alex.bennee@linaro.org> Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest.yml | 19 ++++--------------- docs/about/deprecated.rst | 14 ++++++++++++++ meson.build | 7 ++++++- meson_options.txt | 3 ++- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 0aa149a352..8f332fc36f 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -467,27 +467,16 @@ tsan-build: TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user MAKE_CHECK_ARGS: bench V=1 -# gprof/gcov are GCC features -build-gprof-gcov: +# gcov is a GCC features +gcov: extends: .native_build_job_template needs: job: amd64-ubuntu2004-container + timeout: 80m variables: IMAGE: ubuntu2004 - CONFIGURE_ARGS: --enable-gprof --enable-gcov + CONFIGURE_ARGS: --enable-gcov TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu - artifacts: - expire_in: 1 days - paths: - - build - -check-gprof-gcov: - extends: .native_test_job_template - needs: - - job: build-gprof-gcov - artifacts: true - variables: - IMAGE: ubuntu2004 MAKE_CHECK_ARGS: check after_script: - cd build diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index da2e6fe63d..9317046177 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -20,6 +20,20 @@ they were first deprecated in the 2.10.0 release. What follows is a list of all features currently marked as deprecated. +Build options +------------- + +``gprof`` builds (since 8.0) +'''''''''''''''''''''''''''' + +The ``--enable-gprof`` configure setting relies on compiler +instrumentation to gather its data which can distort the generated +profile. As other non-instrumenting tools are available that give a +more holistic view of the system with non-instrumented binaries we are +deprecating the build option and no longer defend it in CI. The +``--enable-gcov`` build option remains for analysis test case +coverage. + System emulator command line arguments -------------------------------------- diff --git a/meson.build b/meson.build index 0026bba0ce..a76c855312 100644 --- a/meson.build +++ b/meson.build @@ -3805,7 +3805,12 @@ summary_info += {'memory allocator': get_option('malloc')} summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')} summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} -summary_info += {'gprof enabled': get_option('gprof')} +if get_option('gprof') + gprof_info = 'YES (deprecated)' +else + gprof_info = get_option('gprof') +endif +summary_info += {'gprof': gprof_info} summary_info += {'gcov': get_option('b_coverage')} summary_info += {'thread sanitizer': config_host.has_key('CONFIG_TSAN')} summary_info += {'CFI support': get_option('cfi')} diff --git a/meson_options.txt b/meson_options.txt index 56415c5c23..7e5801db90 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -320,7 +320,8 @@ option('debug_stack_usage', type: 'boolean', value: false, option('qom_cast_debug', type: 'boolean', value: false, description: 'cast debugging support') option('gprof', type: 'boolean', value: false, - description: 'QEMU profiling with gprof') + description: 'QEMU profiling with gprof', + deprecated: true) option('profiler', type: 'boolean', value: false, description: 'profiler support') option('slirp_smbd', type : 'feature', value : 'auto', From 77034bbc120281a981f7371ab642762a33cceaea Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 9 Feb 2023 13:50:47 +0000 Subject: [PATCH 700/814] tests/qtest/npcm7xx_pwm-test: Be less verbose unless V=2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The npcm7xx_pwm-test produces a lot of output at V=1, which means that on our CI tests the log files exceed the gitlab 500KB limit. Suppress the messages about exactly what is being tested unless at V=2 and above. This follows the pattern we use with qom-test. Signed-off-by: Peter Maydell Message-Id: <20230209135047.1753081-1-peter.maydell@linaro.org> Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/qtest/npcm7xx_pwm-test.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c index e320a625c4..ea4ca1d106 100644 --- a/tests/qtest/npcm7xx_pwm-test.c +++ b/tests/qtest/npcm7xx_pwm-test.c @@ -20,6 +20,8 @@ #include "qapi/qmp/qdict.h" #include "qapi/qmp/qnum.h" +static int verbosity_level; + #define REF_HZ 25000000 /* Register field definitions. */ @@ -221,7 +223,9 @@ static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name) QDict *response; uint64_t val; - g_test_message("Getting properties %s from %s", name, path); + if (verbosity_level >= 2) { + g_test_message("Getting properties %s from %s", name, path); + } response = qtest_qmp(qts, "{ 'execute': 'qom-get'," " 'arguments': { 'path': %s, 'property': %s}}", path, name); @@ -260,8 +264,10 @@ static void mft_qom_set(QTestState *qts, int index, const char *name, QDict *response; char *path = g_strdup_printf("/machine/soc/mft[%d]", index); - g_test_message("Setting properties %s of mft[%d] with value %u", - name, index, value); + if (verbosity_level >= 2) { + g_test_message("Setting properties %s of mft[%d] with value %u", + name, index, value); + } response = qtest_qmp(qts, "{ 'execute': 'qom-set'," " 'arguments': { 'path': %s, " " 'property': %s, 'value': %u}}", @@ -506,9 +512,12 @@ static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty) int32_t expected_cnt = mft_compute_cnt(rpm, clk); qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic"); - g_test_message( - "verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 ", rpm: %u, cnt: %d", - index, clk, duty, rpm, expected_cnt); + if (verbosity_level >= 2) { + g_test_message( + "verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 + ", rpm: %u, cnt: %d", + index, clk, duty, rpm, expected_cnt); + } /* Verify rpm for fan A */ /* Stop capture */ @@ -670,6 +679,12 @@ int main(int argc, char **argv) { TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)]; + char *v_env = getenv("V"); + + if (v_env) { + verbosity_level = atoi(v_env); + } + g_test_init(&argc, &argv, NULL); for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) { From b482fb43deb3fa9f5c44fd3da3dde04acec7750f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 9 Feb 2023 17:15:40 +0100 Subject: [PATCH 701/814] hw/misc/sga: Remove the deprecated "sga" device It's been deprecated since QEMU v6.2, so it should be OK to finally remove this now. Message-Id: <20230209161540.1054669-1-thuth@redhat.com> Reviewed-by: Juan Quintela Acked-by: Gerd Hoffmann Signed-off-by: Thomas Huth --- .gitmodules | 3 -- MAINTAINERS | 1 - docs/about/deprecated.rst | 9 ---- docs/about/removed-features.rst | 10 ++++ hw/i386/Kconfig | 1 - hw/misc/Kconfig | 4 -- hw/misc/meson.build | 1 - hw/misc/sga.c | 71 ---------------------------- pc-bios/README | 6 --- pc-bios/meson.build | 1 - pc-bios/sgabios.bin | Bin 4096 -> 0 bytes roms/Makefile | 9 +--- roms/sgabios | 1 - tests/migration/guestperf/engine.py | 2 +- 14 files changed, 12 insertions(+), 107 deletions(-) delete mode 100644 hw/misc/sga.c delete mode 100644 pc-bios/sgabios.bin delete mode 160000 roms/sgabios diff --git a/.gitmodules b/.gitmodules index 24cffa87d4..6ce5bf49c5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,6 @@ [submodule "roms/qemu-palcode"] path = roms/qemu-palcode url = https://gitlab.com/qemu-project/qemu-palcode.git -[submodule "roms/sgabios"] - path = roms/sgabios - url = https://gitlab.com/qemu-project/sgabios.git [submodule "dtc"] path = dtc url = https://gitlab.com/qemu-project/dtc.git diff --git a/MAINTAINERS b/MAINTAINERS index 96e25f62ac..fd54c1f140 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1676,7 +1676,6 @@ F: hw/acpi/piix4.c F: hw/acpi/ich9*.c F: include/hw/acpi/ich9*.h F: include/hw/southbridge/piix.h -F: hw/misc/sga.c F: hw/isa/apm.c F: include/hw/isa/apm.h F: tests/unit/test-x86-cpuid.c diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 9317046177..cb1ec72347 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -260,15 +260,6 @@ full SCSI support. Use virtio-scsi instead when SCSI passthrough is required. Note this also applies to ``-device virtio-blk-pci,scsi=on|off``, which is an alias. -``-device sga`` (since 6.2) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``sga`` device loads an option ROM for x86 targets which enables -SeaBIOS to send messages to the serial console. SeaBIOS 1.11.0 onwards -contains native support for this feature and thus use of the option -ROM approach is obsolete. The native SeaBIOS support can be activated -by using ``-machine graphics=off``. - ``-device nvme-ns,eui64-default=on|off`` (since 7.1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index a17d0554d6..4a84e6174f 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -789,6 +789,16 @@ The 'ide-drive' device has been removed. Users should use 'ide-hd' or The 'scsi-disk' device has been removed. Users should use 'scsi-hd' or 'scsi-cd' as appropriate to get a SCSI hard disk or CD-ROM as needed. +``sga`` (removed in 8.0) +'''''''''''''''''''''''' + +The ``sga`` device loaded an option ROM for x86 targets which enabled +SeaBIOS to send messages to the serial console. SeaBIOS 1.11.0 onwards +contains native support for this feature and thus use of the option +ROM approach was obsolete. The native SeaBIOS support can be activated +by using ``-machine graphics=off``. + + Related binaries ---------------- diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 1bf47b0b0b..9fbfe748b5 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -26,7 +26,6 @@ config PC imply QXL imply SEV imply SGX - imply SGA imply TEST_DEVICES imply TPM_CRB imply TPM_TIS_ISA diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index eaeddca277..2ef5781ef8 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -15,10 +15,6 @@ config ISA_DEBUG bool depends on ISA_BUS -config SGA - bool - depends on ISA_BUS - config ISA_TESTDEV bool default y if TEST_DEVICES diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 448e14b531..fe869b98ca 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -5,7 +5,6 @@ softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c')) softmmu_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c')) softmmu_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c')) softmmu_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c')) -softmmu_ss.add(when: 'CONFIG_SGA', if_true: files('sga.c')) softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) diff --git a/hw/misc/sga.c b/hw/misc/sga.c deleted file mode 100644 index 1d04672b01..0000000000 --- a/hw/misc/sga.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * QEMU dummy ISA device for loading sgabios option rom. - * - * Copyright (c) 2011 Glauber Costa, Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * sgabios code originally available at code.google.com/p/sgabios - * - */ - -#include "qemu/osdep.h" -#include "hw/isa/isa.h" -#include "hw/loader.h" -#include "qemu/module.h" -#include "qom/object.h" -#include "qemu/error-report.h" - -#define SGABIOS_FILENAME "sgabios.bin" - -#define TYPE_SGA "sga" -OBJECT_DECLARE_SIMPLE_TYPE(ISASGAState, SGA) - -struct ISASGAState { - ISADevice parent_obj; -}; - -static void sga_realizefn(DeviceState *dev, Error **errp) -{ - warn_report("-device sga is deprecated, use -machine graphics=off"); - rom_add_vga(SGABIOS_FILENAME); -} - -static void sga_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->realize = sga_realizefn; - dc->desc = "Serial Graphics Adapter"; -} - -static const TypeInfo sga_info = { - .name = TYPE_SGA, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISASGAState), - .class_init = sga_class_initfn, -}; - -static void sga_register_types(void) -{ - type_register_static(&sga_info); -} - -type_init(sga_register_types) diff --git a/pc-bios/README b/pc-bios/README index b94f3fb081..3702ed485c 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -20,12 +20,6 @@ -machine pseries,x-vof=on. When enabled, the firmware acts as a slim shim and QEMU implements parts of the IEEE 1275 Open Firmware interface. -- sgabios (the Serial Graphics Adapter option ROM) provides a means for - legacy x86 software to communicate with an attached serial console as - if a video card were attached. The master sources reside in a subversion - repository at http://sgabios.googlecode.com/svn/trunk. A git mirror is - available at https://gitlab.com/qemu-project/sgabios.git. - - The PXE roms come from the iPXE project. Built with BANNER_TIME 0. Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: diff --git a/pc-bios/meson.build b/pc-bios/meson.build index 388e0db6e4..a7224ef469 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -28,7 +28,6 @@ blobs = [ 'bios-256k.bin', 'bios-microvm.bin', 'qboot.rom', - 'sgabios.bin', 'vgabios.bin', 'vgabios-cirrus.bin', 'vgabios-stdvga.bin', diff --git a/pc-bios/sgabios.bin b/pc-bios/sgabios.bin deleted file mode 100644 index 6308f2e2d7064b52ff3c2e207b71018710866c05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmeHJYj6|S6+T+YT3ay^1p*W&k_e7su)Rpan3r(;;AI|>ECIE(;9|fcW)hp&yG)XC zjT`~pwGxIlX&!Cb@<VM?hJDpa$QYM6@}ETh^4R$)P8@z z!nMi-3!9oYJW*d@u54V#fTzB>q3#Lu!sfb7k2kDqF_*2c+r-s3o2^At?K7s@W`Jj5 zS$U}7*@ni3()CS^4bRqdT*GAZhK44yeTKPiQ?uD_waq9nTW2!U zika!iRxGao*Z3UPHpf1_xH*T#Sz(KE*y2W5Uf=xWY%|O+pI3(P)r~>iOnRF24;Yfa z9bmLF=1~(L(vQo1*z$mF{Pzu`O=HGR{a)ey1*-gY;LqqF@uKEsxs8{ zZFTzb;9*EAO2tPI}3h$TkK;tS5t zV0?QgP_(Hof}Vz5_k6`3#usEJP)rc*0@3??Sy#C-OYp(=1o&HKI!16sj!d4;I>!|( ziJ5)xg9^e1yU*ow`)sFuA~9ISq4fgo^ZKd{)(VUGU?582Y}lJ=J$7s(4cTykB?yfU@0L8Qj=( zO?`T>y)mWv~cqb~($zg~e8~n7)cFZi8jc3Rs5qg3Ik;f@8;1fo_#G zJQ(PvLN5-c6^B(IoE;Qym){Ws-RjV2TvvtE_Y_n}HOP9aBX|8XzIMnFw})JlIZLOC zdnm2`y3@~J6}pXj)8QfLHRWy*jtVCoTX-szxh>3kBUQFzm#>nKWIr-g*A*3j=n!66OY_!zBnxOrE43k!QwqwTBo1W=59H> zQ`PG*w`dM;QuUhHh=b+~j!f=8hmNE1R;kGuIYJ6kw;3((#y9>WNX-)6DF#2cVf|IuNAe%ltXjK2a<4-yeXs7-QKNIkxO!D5$Tk$cmDn@My<=^-dIZOO_te4A8-zTg61>O zF;*y?KRl8W`f}-BpH}Mjp5bs(^P0Isgy%ck`hw>CL3jM^+4`z+;Fku?%L*6I1&gK34)`iT| zJdN$#nX;bq%PQnLvNdIu{Rx@V`4bYK9m*svDV!P=i-clfCTr8yGOr_kDO5&0=zuS7 zHF-(8^YrlvV_x1AnXEw6NwS7h-suLC%Pi)=`d{8Y$8 zW+c6}5!dz$L`-eJpybFp#*gvKG;bjDltAN@K%t$X&Fje*^Da759KdD9>K-3}@p`PZc*j|4!6UCdT z&O$6k)FDno)Fb8~8W6h>M z6;g^srw|vCiwdbmVgO52n+MO(mgn_T6kY(W3TG5v3M318xx!trMbWzzUJbnp_X6n~ zCIxXm(RC0ApV(N6ZKwa_0AM!V?VZ`d@Rb4K4Yi zxd!3KM`>tS+KyAIB%quQnT zwcexk0sZ_(QSAo&j@#P+7;@KEkiyKK5GZGz5iAFQJa~(IaI5PCki~Ikx0%}BN1lq~ sdHWIm-;fP)vNNuH6aD$#=ivVszx^`*j(yjG?>g{*?7(A{OXX?*0eG=(c>n+a diff --git a/roms/Makefile b/roms/Makefile index 5e44d97890..955f92286d 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -57,7 +57,6 @@ default help: @echo "available build targets:" @echo " bios -- update bios.bin (seabios)" @echo " vgabios -- update vgabios binaries (seabios)" - @echo " sgabios -- update sgabios binaries" @echo " pxerom -- update nic roms (bios only)" @echo " efirom -- update nic roms (bios+efi)" @echo " slof -- update slof.bin" @@ -102,11 +101,7 @@ build-seabios-config-%: config.% OUT=$(CURDIR)/seabios/builds/$*/ all -.PHONY: sgabios skiboot qboot -sgabios: - $(MAKE) -C sgabios - cp sgabios/sgabios.bin ../pc-bios - +.PHONY: skiboot qboot pxerom: $(patsubst %,pxe-rom-%,$(pxerom_variants)) @@ -199,8 +194,6 @@ npcm7xx_bootrom: clean: rm -rf seabios/.config seabios/out seabios/builds - $(MAKE) -C sgabios clean - rm -f sgabios/.depend $(MAKE) -C ipxe/src veryclean $(MAKE) -C edk2/BaseTools clean $(MAKE) -C SLOF clean diff --git a/roms/sgabios b/roms/sgabios deleted file mode 160000 index cbaee52287..0000000000 --- a/roms/sgabios +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cbaee52287e5f32373181cff50a00b6c4ac9015a diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index cc06fac592..e69d16a62c 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -337,7 +337,7 @@ class Engine(object): argv.extend(self._get_qemu_serial_args()) if self._debug: - argv.extend(["-device", "sga"]) + argv.extend(["-machine", "graphics=off"]) if hardware._prealloc_pages: argv_source += ["-mem-path", "/dev/shm", From 8c6631e66e323bc92e0ea5d235e7059b30fb86ee Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 10 Feb 2023 12:23:15 +0100 Subject: [PATCH 702/814] include/hw: Do not include "hw/registerfields.h" in headers that don't need it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include "hw/registerfields.h" in the .c files instead (if needed). Message-Id: <20230210112315.1116966-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- hw/char/ibex_uart.c | 1 + hw/ssi/ibex_spi_host.c | 1 + include/hw/arm/smmuv3.h | 1 - include/hw/char/ibex_uart.h | 1 - include/hw/ssi/ibex_spi_host.h | 1 - 5 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index e58181fcf4..f70adb5308 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -31,6 +31,7 @@ #include "hw/qdev-clock.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" +#include "hw/registerfields.h" #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c index 57df462e3c..1ee7d88c22 100644 --- a/hw/ssi/ibex_spi_host.c +++ b/hw/ssi/ibex_spi_host.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/module.h" +#include "hw/registerfields.h" #include "hw/ssi/ibex_spi_host.h" #include "hw/irq.h" #include "hw/qdev-properties.h" diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index f1921fdf9e..b6dd087526 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -20,7 +20,6 @@ #define HW_ARM_SMMUV3_H #include "hw/arm/smmu-common.h" -#include "hw/registerfields.h" #include "qom/object.h" #define TYPE_SMMUV3_IOMMU_MEMORY_REGION "smmuv3-iommu-memory-region" diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h index a39985516a..9deadf223b 100644 --- a/include/hw/char/ibex_uart.h +++ b/include/hw/char/ibex_uart.h @@ -26,7 +26,6 @@ #define HW_IBEX_UART_H #include "hw/sysbus.h" -#include "hw/registerfields.h" #include "chardev/char-fe.h" #include "qemu/timer.h" #include "qom/object.h" diff --git a/include/hw/ssi/ibex_spi_host.h b/include/hw/ssi/ibex_spi_host.h index 1f6d077766..8089cc1c31 100644 --- a/include/hw/ssi/ibex_spi_host.h +++ b/include/hw/ssi/ibex_spi_host.h @@ -32,7 +32,6 @@ #include "hw/ssi/ssi.h" #include "qemu/fifo8.h" #include "qom/object.h" -#include "hw/registerfields.h" #include "qemu/timer.h" #define TYPE_IBEX_SPI_HOST "ibex-spi" From 5feed38c2139a2cea46b4b540303ef255d4cafc7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 10 Feb 2023 12:19:31 +0100 Subject: [PATCH 703/814] Do not include "qemu/error-report.h" in headers that do not need it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include it in the .c files instead that use the error reporting functions. Message-Id: <20230210111931.1115489-1-thuth@redhat.com> Reviewed-by: Markus Armbruster Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- hw/display/vhost-user-gpu.c | 1 + hw/display/virtio-gpu-udmabuf.c | 1 + hw/display/virtio-gpu-virgl.c | 1 + hw/misc/applesmc.c | 1 + include/hw/arm/allwinner-a10.h | 1 - include/qemu/vhost-user-server.h | 1 - include/ui/console.h | 1 - ui/console.c | 1 + ui/dbus-clipboard.c | 1 + ui/dbus-console.c | 1 + ui/dbus-listener.c | 1 + ui/dbus.c | 1 + ui/egl-headless.c | 1 + ui/gtk.c | 1 + ui/spice-app.c | 1 + ui/spice-display.c | 1 + ui/udmabuf.c | 1 + ui/vdagent.c | 1 + util/vhost-user-server.c | 1 + 19 files changed, 16 insertions(+), 3 deletions(-) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 4380a5e672..71dfd956b8 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -11,6 +11,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/sockets.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio-gpu.h" diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 847fa4c0cc..69e2cf0bd6 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/units.h" #include "qemu/iov.h" #include "ui/console.h" diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 73cb92c8d5..1c47603d40 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/iov.h" #include "trace.h" #include "hw/virtio/virtio.h" diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 5f9c742e50..72300d0cbc 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -34,6 +34,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "ui/console.h" +#include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/timer.h" #include "qom/object.h" diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index e0f2f7ab19..79e0c80568 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -1,7 +1,6 @@ #ifndef HW_ARM_ALLWINNER_A10_H #define HW_ARM_ALLWINNER_A10_H -#include "qemu/error-report.h" #include "hw/char/serial.h" #include "hw/arm/boot.h" #include "hw/pci/pci_device.h" diff --git a/include/qemu/vhost-user-server.h b/include/qemu/vhost-user-server.h index cd43193b80..25c72433ca 100644 --- a/include/qemu/vhost-user-server.h +++ b/include/qemu/vhost-user-server.h @@ -15,7 +15,6 @@ #include "io/channel-socket.h" #include "io/channel-file.h" #include "io/net-listener.h" -#include "qemu/error-report.h" #include "qapi/error.h" #include "standard-headers/linux/virtio_blk.h" diff --git a/include/ui/console.h b/include/ui/console.h index 8e6cf782a1..1cb53acc33 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -4,7 +4,6 @@ #include "ui/qemu-pixman.h" #include "qom/object.h" #include "qemu/notify.h" -#include "qemu/error-report.h" #include "qapi/qapi-types-ui.h" #ifdef CONFIG_OPENGL diff --git a/ui/console.c b/ui/console.c index ab43561fe1..98b701f5a3 100644 --- a/ui/console.c +++ b/ui/console.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qapi/qapi-commands-ui.h" #include "qemu/coroutine.h" +#include "qemu/error-report.h" #include "qemu/fifo8.h" #include "qemu/main-loop.h" #include "qemu/module.h" diff --git a/ui/dbus-clipboard.c b/ui/dbus-clipboard.c index 5843d26cd2..df9a754a8d 100644 --- a/ui/dbus-clipboard.c +++ b/ui/dbus-clipboard.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" #include "qemu/dbus.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qom/object_interfaces.h" #include "sysemu/sysemu.h" diff --git a/ui/dbus-console.c b/ui/dbus-console.c index 898a4ac8a5..0bfaa2298d 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "ui/input.h" #include "ui/kbd-state.h" diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index f9fc8eda51..57d4e401db 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "dbus.h" #include diff --git a/ui/dbus.c b/ui/dbus.c index 32d88dc94a..f2dcba03d0 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "qemu/dbus.h" #include "qemu/main-loop.h" #include "qemu/option.h" diff --git a/ui/egl-headless.c b/ui/egl-headless.c index 7a30fd9777..ae07e91302 100644 --- a/ui/egl-headless.c +++ b/ui/egl-headless.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/module.h" #include "sysemu/sysemu.h" #include "ui/console.h" diff --git a/ui/gtk.c b/ui/gtk.c index 7f752d8b7d..fd82e9b1ca 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -36,6 +36,7 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "ui/console.h" diff --git a/ui/spice-app.c b/ui/spice-app.c index 7e71e18da9..ad7f0551ad 100644 --- a/ui/spice-app.c +++ b/ui/spice-app.c @@ -29,6 +29,7 @@ #include "ui/console.h" #include "ui/spice-display.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/cutils.h" #include "qemu/module.h" diff --git a/ui/spice-display.c b/ui/spice-display.c index 0616a6982f..16802f99cb 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" #include "ui/qemu-spice.h" +#include "qemu/error-report.h" #include "qemu/timer.h" #include "qemu/lockable.h" #include "qemu/main-loop.h" diff --git a/ui/udmabuf.c b/ui/udmabuf.c index cbf4357bb1..6a0a11a85d 100644 --- a/ui/udmabuf.c +++ b/ui/udmabuf.c @@ -7,6 +7,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" +#include "qemu/error-report.h" #include diff --git a/ui/vdagent.c b/ui/vdagent.c index 1f51a78da1..8a651492f0 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -2,6 +2,7 @@ #include "qapi/error.h" #include "chardev/char.h" #include "qemu/buffer.h" +#include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/units.h" #include "hw/qdev-core.h" diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c index 145eb17c08..40f36ea214 100644 --- a/util/vhost-user-server.c +++ b/util/vhost-user-server.c @@ -8,6 +8,7 @@ * later. See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/vhost-user-server.h" #include "block/aio-wait.h" From 8f75703462e389b55755b98c250b5aa62685c0d3 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:49 -0300 Subject: [PATCH 704/814] tests/qtest: Skip PXE tests for missing devices Check if the devices we're trying to add are present in the QEMU binary. They could have been removed from the build via Kconfig or the --without-default-devices option. Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-2-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/pxe-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/pxe-test.c b/tests/qtest/pxe-test.c index 52f0b5c67c..62b6eef464 100644 --- a/tests/qtest/pxe-test.c +++ b/tests/qtest/pxe-test.c @@ -108,6 +108,10 @@ static void test_batch(const testdef_t *tests, bool ipv6) const testdef_t *test = &tests[i]; char *testname; + if (!qtest_has_device(test->model)) { + continue; + } + testname = g_strdup_printf("pxe/ipv4/%s/%s", test->machine, test->model); qtest_add_data_func(testname, test, test_pxe_ipv4); From dee66bc9691a0d5e8337c24b5cf303f46293df76 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:50 -0300 Subject: [PATCH 705/814] tests/qtest: Do not run lsi53c895a test if device is not present The tests are built once for all the targets, so as long as one QEMU binary is built with CONFIG_LSI_SCSI_PCI=y, this test will run. However some binaries might not include the device. So check this again in runtime. Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-3-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/fuzz-lsi53c895a-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c index 392a7ae7ed..a9254b455d 100644 --- a/tests/qtest/fuzz-lsi53c895a-test.c +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -112,6 +112,10 @@ static void test_lsi_do_dma_empty_queue(void) int main(int argc, char **argv) { + if (!qtest_has_device("lsi53c895a")) { + return 0; + } + g_test_init(&argc, &argv, NULL); qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", From 56f7c6b15669a8bcf3236c7dffba0fa388a2dd6d Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:51 -0300 Subject: [PATCH 706/814] tests/qtest: Add dependence on PCIE_PORT for virtio-net-failover.c This test depends on the presence of the pcie-root-port device. Add a build time dependency. Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-4-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index e97616d327..5c8b031ce0 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -73,7 +73,8 @@ qtests_i386 = \ (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \ (config_host.has_key('CONFIG_POSIX') and \ config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \ - (config_all_devices.has_key('CONFIG_VIRTIO_NET') and \ + (config_all_devices.has_key('CONFIG_PCIE_PORT') and \ + config_all_devices.has_key('CONFIG_VIRTIO_NET') and \ config_all_devices.has_key('CONFIG_Q35') and \ config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \ slirp.found() ? ['virtio-net-failover'] : []) + \ From a2da5e2f306c1120dad66c4f2b8bb4084a225ac2 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:53 -0300 Subject: [PATCH 707/814] tests/qtest: hd-geo-test: Check for missing devices Don't include tests that require devices not available in the QEMU binary. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Message-Id: <20230208194700.11035-6-farosas@suse.de> Signed-off-by: Thomas Huth --- tests/qtest/hd-geo-test.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c index 4a7628077b..5aa258a2b3 100644 --- a/tests/qtest/hd-geo-test.c +++ b/tests/qtest/hd-geo-test.c @@ -1090,30 +1090,42 @@ int main(int argc, char **argv) qtest_add_func("hd-geo/override/ide", test_override_ide); if (qtest_has_device("lsi53c895a")) { qtest_add_func("hd-geo/override/scsi", test_override_scsi); - qtest_add_func("hd-geo/override/scsi_2_controllers", - test_override_scsi_2_controllers); + if (qtest_has_device("virtio-scsi-pci")) { + qtest_add_func("hd-geo/override/scsi_2_controllers", + test_override_scsi_2_controllers); + } } - qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk); qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs); - qtest_add_func("hd-geo/override/scsi_hot_unplug", - test_override_scsi_hot_unplug); - qtest_add_func("hd-geo/override/virtio_hot_unplug", - test_override_virtio_hot_unplug); + if (qtest_has_device("virtio-scsi-pci")) { + qtest_add_func("hd-geo/override/scsi_hot_unplug", + test_override_scsi_hot_unplug); + } + if (qtest_has_device("virtio-blk-pci")) { + qtest_add_func("hd-geo/override/virtio_hot_unplug", + test_override_virtio_hot_unplug); + qtest_add_func("hd-geo/override/virtio_blk", + test_override_virtio_blk); + } if (qtest_has_machine("q35")) { qtest_add_func("hd-geo/override/sata", test_override_sata); - qtest_add_func("hd-geo/override/virtio_blk_q35", - test_override_virtio_blk_q35); qtest_add_func("hd-geo/override/zero_chs_q35", test_override_zero_chs_q35); if (qtest_has_device("lsi53c895a")) { qtest_add_func("hd-geo/override/scsi_q35", test_override_scsi_q35); } - qtest_add_func("hd-geo/override/scsi_hot_unplug_q35", - test_override_scsi_hot_unplug_q35); - qtest_add_func("hd-geo/override/virtio_hot_unplug_q35", - test_override_virtio_hot_unplug_q35); + if (qtest_has_device("virtio-scsi-pci")) { + qtest_add_func("hd-geo/override/scsi_hot_unplug_q35", + test_override_scsi_hot_unplug_q35); + } + if (qtest_has_device("virtio-blk-pci")) { + qtest_add_func("hd-geo/override/virtio_hot_unplug_q35", + test_override_virtio_hot_unplug_q35); + qtest_add_func("hd-geo/override/virtio_blk_q35", + test_override_virtio_blk_q35); + } + } } else { g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; " From ca7d9f5f28770af787e11a0300d6ecb3883cbfaa Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:54 -0300 Subject: [PATCH 708/814] test/qtest: Fix coding style in device-plug-test.c We should not mix declarations and statements in QEMU code. Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-7-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/device-plug-test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 5a6afa2b57..4f92617335 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -64,6 +64,7 @@ static void process_device_remove(QTestState *qtest, const char *id) static void test_pci_unplug_request(void) { + QTestState *qtest; const char *arch = qtest_get_arch(); const char *machine_addition = ""; @@ -71,8 +72,8 @@ static void test_pci_unplug_request(void) machine_addition = "-machine pc"; } - QTestState *qtest = qtest_initf("%s -device virtio-mouse-pci,id=dev0", - machine_addition); + qtest = qtest_initf("%s -device virtio-mouse-pci,id=dev0", + machine_addition); process_device_remove(qtest, "dev0"); @@ -94,6 +95,7 @@ static void test_q35_pci_unplug_request(void) static void test_pci_unplug_json_request(void) { + QTestState *qtest; const char *arch = qtest_get_arch(); const char *machine_addition = ""; @@ -101,7 +103,7 @@ static void test_pci_unplug_json_request(void) machine_addition = "-machine pc"; } - QTestState *qtest = qtest_initf( + qtest = qtest_initf( "%s -device \"{'driver': 'virtio-mouse-pci', 'id': 'dev0'}\"", machine_addition); From 45ec78befbd3aa632d51d4efb52f07d26f1eaa15 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:55 -0300 Subject: [PATCH 709/814] tests/qtest: Skip unplug tests that use missing devices Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-8-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/device-plug-test.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 4f92617335..01cecd6e20 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -68,6 +68,11 @@ static void test_pci_unplug_request(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!qtest_has_device("virtio-mouse-pci")) { + g_test_skip("Device virtio-mouse-pci not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -82,11 +87,17 @@ static void test_pci_unplug_request(void) static void test_q35_pci_unplug_request(void) { + QTestState *qtest; - QTestState *qtest = qtest_initf("-machine q35 " - "-device pcie-root-port,id=p1 " - "-device pcie-pci-bridge,bus=p1,id=b1 " - "-device virtio-mouse-pci,bus=b1,id=dev0"); + if (!qtest_has_device("virtio-mouse-pci")) { + g_test_skip("Device virtio-mouse-pci not available"); + return; + } + + qtest = qtest_initf("-machine q35 " + "-device pcie-root-port,id=p1 " + "-device pcie-pci-bridge,bus=p1,id=b1 " + "-device virtio-mouse-pci,bus=b1,id=dev0"); process_device_remove(qtest, "dev0"); @@ -99,6 +110,11 @@ static void test_pci_unplug_json_request(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!qtest_has_device("virtio-mouse-pci")) { + g_test_skip("Device virtio-mouse-pci not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -114,6 +130,7 @@ static void test_pci_unplug_json_request(void) static void test_q35_pci_unplug_json_request(void) { + QTestState *qtest; const char *port = "-device \"{'driver': 'pcie-root-port', " "'id': 'p1'}\""; @@ -125,8 +142,12 @@ static void test_q35_pci_unplug_json_request(void) "'bus': 'b1', " "'id': 'dev0'}\""; - QTestState *qtest = qtest_initf("-machine q35 %s %s %s", - port, bridge, device); + if (!qtest_has_device("virtio-mouse-pci")) { + g_test_skip("Device virtio-mouse-pci not available"); + return; + } + + qtest = qtest_initf("-machine q35 %s %s %s", port, bridge, device); process_device_remove(qtest, "dev0"); From 184c16d1acd4e04392e5a97654212b71a1551638 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:56 -0300 Subject: [PATCH 710/814] tests/qtest: drive_del-test: Skip tests that require missing devices Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-9-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/drive_del-test.c | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index 9a750395a9..8a6f3ac963 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -16,6 +16,8 @@ #include "qapi/qmp/qdict.h" #include "qapi/qmp/qlist.h" +static const char *qvirtio_get_dev_type(void); + static bool look_for_drive0(QTestState *qts, const char *command, const char *key) { QDict *response; @@ -40,6 +42,19 @@ static bool look_for_drive0(QTestState *qts, const char *command, const char *ke return found; } +/* + * This covers the possible absence of a device due to QEMU build + * options. + */ +static bool has_device_builtin(const char *dev) +{ + gchar *device = g_strdup_printf("%s-%s", dev, qvirtio_get_dev_type()); + bool rc = qtest_has_device(device); + + g_free(device); + return rc; +} + static bool has_drive(QTestState *qts) { return look_for_drive0(qts, "query-block", "device"); @@ -208,6 +223,11 @@ static void test_drive_del_device_del(void) { QTestState *qts; + if (!has_device_builtin("virtio-scsi")) { + g_test_skip("Device virtio-scsi is not available"); + return; + } + /* Start with a drive used by a device that unplugs instantaneously */ qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," "file.read-zeroes=on,format=raw" @@ -232,6 +252,11 @@ static void test_cli_device_del(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -256,6 +281,11 @@ static void test_cli_device_del_q35(void) { QTestState *qts; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + /* * -drive/-device and device_del. Start with a drive used by a * device that unplugs after reset. @@ -277,6 +307,11 @@ static void test_empty_device_del(void) { QTestState *qts; + if (!has_device_builtin("virtio-scsi")) { + g_test_skip("Device virtio-scsi is not available"); + return; + } + /* device_del with no drive plugged. */ qts = qtest_initf("-device virtio-scsi-%s -device scsi-cd,id=dev0", qvirtio_get_dev_type()); @@ -291,6 +326,11 @@ static void test_device_add_and_del(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -330,6 +370,11 @@ static void test_device_add_and_del_q35(void) { QTestState *qts; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + /* * -drive/device_add and device_del. Start with a drive used by a * device that unplugs after reset. @@ -352,6 +397,11 @@ static void test_drive_add_device_add_and_del(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -374,6 +424,11 @@ static void test_drive_add_device_add_and_del_q35(void) { QTestState *qts; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " "-device pcie-pci-bridge,bus=p1,id=b1"); @@ -395,6 +450,11 @@ static void test_blockdev_add_device_add_and_del(void) const char *arch = qtest_get_arch(); const char *machine_addition = ""; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { machine_addition = "-machine pc"; } @@ -417,6 +477,11 @@ static void test_blockdev_add_device_add_and_del_q35(void) { QTestState *qts; + if (!has_device_builtin("virtio-blk")) { + g_test_skip("Device virtio-blk is not available"); + return; + } + qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " "-device pcie-pci-bridge,bus=p1,id=b1"); From c471eb4f40445908c1be7bb11a37ac676a0edae7 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:57 -0300 Subject: [PATCH 711/814] tests/qtest: Check for devices in bios-tables-test Do not include tests that require devices that are not available in the QEMU build. Signed-off-by: Fabiano Rosas Acked-by: Michael S. Tsirkin Message-Id: <20230208194700.11035-10-farosas@suse.de> Signed-off-by: Thomas Huth --- tests/qtest/bios-tables-test.c | 75 ++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index d8c8cda58e..d29a4e47af 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1008,6 +1008,12 @@ static void test_acpi_q35_multif_bridge(void) .machine = MACHINE_Q35, .variant = ".multi-bridge", }; + + if (!qtest_has_device("pcie-root-port")) { + g_test_skip("Device pcie-root-port is not available"); + goto out; + } + test_vm_prepare("-S" " -device virtio-balloon,id=balloon0,addr=0x4.0x2" " -device pcie-root-port,id=rp0,multifunction=on," @@ -1043,6 +1049,7 @@ static void test_acpi_q35_multif_bridge(void) /* check that reboot/reset doesn't change any ACPI tables */ qtest_qmp_send(data.qts, "{'execute':'system_reset' }"); process_acpi_tables(&data); +out: free_test_data(&data); } @@ -1396,6 +1403,11 @@ static void test_acpi_tcg_dimm_pxm(const char *machine) { test_data data; + if (!qtest_has_device("nvdimm")) { + g_test_skip("Device nvdimm is not available"); + return; + } + memset(&data, 0, sizeof(data)); data.machine = machine; data.variant = ".dimmpxm"; @@ -1444,6 +1456,11 @@ static void test_acpi_virt_tcg_memhp(void) .scan_len = 256ULL * 1024 * 1024, }; + if (!qtest_has_device("nvdimm")) { + g_test_skip("Device nvdimm is not available"); + goto out; + } + data.variant = ".memhp"; test_acpi_one(" -machine nvdimm=on" " -cpu cortex-a57" @@ -1457,7 +1474,7 @@ static void test_acpi_virt_tcg_memhp(void) " -device pc-dimm,id=dimm0,memdev=ram2,node=0" " -device nvdimm,id=dimm1,memdev=nvm0,node=1", &data); - +out: free_test_data(&data); } @@ -1475,6 +1492,11 @@ static void test_acpi_microvm_tcg(void) { test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off", &data); @@ -1485,6 +1507,11 @@ static void test_acpi_microvm_usb_tcg(void) { test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); data.variant = ".usb"; test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,usb=on,rtc=off", @@ -1496,6 +1523,11 @@ static void test_acpi_microvm_rtc_tcg(void) { test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); data.variant = ".rtc"; test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=on", @@ -1507,6 +1539,11 @@ static void test_acpi_microvm_pcie_tcg(void) { test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); data.variant = ".pcie"; data.tcg_only = true; /* need constant host-phys-bits */ @@ -1519,6 +1556,11 @@ static void test_acpi_microvm_ioapic2_tcg(void) { test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); data.variant = ".ioapic2"; test_acpi_one(" -machine microvm,acpi=on,ioapic2=on,rtc=off", @@ -1558,6 +1600,12 @@ static void test_acpi_virt_tcg_pxb(void) .ram_start = 0x40000000ULL, .scan_len = 128ULL * 1024 * 1024, }; + + if (!qtest_has_device("pcie-root-port")) { + g_test_skip("Device pcie-root-port is not available"); + goto out; + } + /* * While using -cdrom, the cdrom would auto plugged into pxb-pcie, * the reason is the bus of pxb-pcie is also root bus, it would lead @@ -1576,7 +1624,7 @@ static void test_acpi_virt_tcg_pxb(void) " -cpu cortex-a57" " -device pxb-pcie,bus_nr=128", &data); - +out: free_test_data(&data); } @@ -1764,6 +1812,12 @@ static void test_acpi_microvm_acpi_erst(void) gchar *params; test_data data; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + g_free(tmp_path); + return; + } + test_acpi_microvm_prepare(&data); data.variant = ".pcie"; data.tcg_only = true; /* need constant host-phys-bits */ @@ -1824,6 +1878,11 @@ static void test_acpi_q35_viot(void) .variant = ".viot", }; + if (!qtest_has_device("virtio-iommu")) { + g_test_skip("Device virtio-iommu is not available"); + goto out; + } + /* * To keep things interesting, two buses bypass the IOMMU. * VIOT should only describes the other two buses. @@ -1834,6 +1893,7 @@ static void test_acpi_q35_viot(void) "-device pxb-pcie,bus_nr=0x20,id=pcie.200,bus=pcie.0,bypass_iommu=on " "-device pxb-pcie,bus_nr=0x30,id=pcie.300,bus=pcie.0", &data); +out: free_test_data(&data); } @@ -1894,8 +1954,10 @@ static void test_acpi_virt_viot(void) .scan_len = 128ULL * 1024 * 1024, }; - test_acpi_one("-cpu cortex-a57 " - "-device virtio-iommu-pci", &data); + if (qtest_has_device("virtio-iommu")) { + test_acpi_one("-cpu cortex-a57 " + "-device virtio-iommu-pci", &data); + } free_test_data(&data); } @@ -2004,6 +2066,11 @@ static void test_acpi_microvm_oem_fields(void) test_data data; char *args; + if (!qtest_has_device("virtio-blk-device")) { + g_test_skip("Device virtio-blk-device is not available"); + return; + } + test_acpi_microvm_prepare(&data); args = test_acpi_create_args(&data, From 628f900883ffae94337ef3ca1c9b70bae267290d Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:58 -0300 Subject: [PATCH 712/814] tests/qtest: Do not include hexloader-test if loader device is not present Signed-off-by: Fabiano Rosas Message-Id: <20230208194700.11035-11-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 5c8b031ce0..e87cb18d8e 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -197,11 +197,11 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \ (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \ + (config_all_devices.has_key('CONFIG_GENERIC_LOADER') ? ['hexloader-test'] : []) + \ ['arm-cpu-features', 'microbit-test', 'test-arm-mptimer', - 'boot-serial-test', - 'hexloader-test'] + 'boot-serial-test'] # TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional qtests_aarch64 = \ From d043f461b3690a70973e0c30a19b9653683deb8e Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:46:59 -0300 Subject: [PATCH 713/814] tests/qemu-iotests: Require virtio-scsi-pci Check that virtio-scsi-pci is present in the QEMU build before running the tests. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Message-Id: <20230208194700.11035-12-farosas@suse.de> Signed-off-by: Thomas Huth --- tests/qemu-iotests/186 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index 072e54e62b..eaf13c7a33 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto file fuse _require_drivers null-co +_require_devices virtio-scsi-pci if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then _notrun "Requires a PC machine" From 2e0def6d37b624c68875800a3092352d11bd0a91 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 8 Feb 2023 16:47:00 -0300 Subject: [PATCH 714/814] tests/qtest: bios-tables-test: Skip if missing configs If we build with --without-default-devices, CONFIG_HPET and CONFIG_PARALLEL are set to N, which makes the respective devices go missing from acpi tables. Signed-off-by: Fabiano Rosas Reviewed-by: Thomas Huth Message-Id: <20230208194700.11035-13-farosas@suse.de> Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index e87cb18d8e..4110f8afc2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -78,7 +78,9 @@ qtests_i386 = \ config_all_devices.has_key('CONFIG_Q35') and \ config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \ slirp.found() ? ['virtio-net-failover'] : []) + \ - (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ + (unpack_edk2_blobs and \ + config_all_devices.has_key('CONFIG_HPET') and \ + config_all_devices.has_key('CONFIG_PARALLEL') ? ['bios-tables-test'] : []) + \ qtests_pci + \ qtests_cxl + \ ['fdc-test', From b8a310a2970aeebea605cdc1ec94b2da035b6e3c Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 18:07:30 -0300 Subject: [PATCH 715/814] tests/qtest: Don't build virtio-serial-test.c if device not present The virtconsole device might not be present in the QEMU build that is being tested. Signed-off-by: Fabiano Rosas Message-Id: <20230213210738.9719-5-farosas@suse.de> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 4110f8afc2..222e1892fb 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -257,10 +257,14 @@ qos_test_ss.add( 'virtio-net-test.c', 'virtio-rng-test.c', 'virtio-scsi-test.c', - 'virtio-serial-test.c', 'virtio-iommu-test.c', 'vmxnet3-test.c', ) + +if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL') + qos_test_ss.add(files('virtio-serial-test.c')) +endif + if config_host.has_key('CONFIG_POSIX') qos_test_ss.add(files('e1000e-test.c')) endif From 1b0e9b9be18210406c9296055cc7f38c6efc26fd Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 31 Jan 2023 19:20:57 +0100 Subject: [PATCH 716/814] tests/tcg/s390x: Use -nostdlib for softmmu tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code currently uses -nostartfiles, but this does not prevent linking with libc. On Fedora there is no cross-libc, so the linking step fails. Fix by using the more comprehensive -nostdlib (that's also what probe_target_compiler() checks for as well). Fixes: 503e549e441e ("tests/tcg/s390x: Test unaligned accesses to lowcore") Signed-off-by: Ilya Leoshkevich Message-Id: <20230131182057.2261614-1-iii@linux.ibm.com> Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- tests/tcg/s390x/Makefile.softmmu-target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target index a34fa68473..50c1b88065 100644 --- a/tests/tcg/s390x/Makefile.softmmu-target +++ b/tests/tcg/s390x/Makefile.softmmu-target @@ -3,7 +3,7 @@ VPATH+=$(S390X_SRC) QEMU_OPTS=-action panic=exit-failure -kernel %: %.S - $(CC) -march=z13 -m64 -nostartfiles -static -Wl,-Ttext=0 \ + $(CC) -march=z13 -m64 -nostdlib -static -Wl,-Ttext=0 \ -Wl,--build-id=none $< -o $@ TESTS += unaligned-lowcore From b1d1d468cabfa800950e1ecb6006df619687c269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 12 Feb 2023 23:51:40 +0100 Subject: [PATCH 717/814] hw/s390x/event-facility: Replace DO_UPCAST(SCLPEvent) by SCLP_EVENT() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the SCLP_EVENT() QOM type-checking macro to avoid DO_UPCAST(). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230212225144.58660-16-philmd@linaro.org> Reviewed-by: Thomas Huth Reviewed-by: Eric Farman Signed-off-by: Thomas Huth --- hw/s390x/event-facility.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index faa51aa4c7..6891e3cd73 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -64,8 +64,7 @@ static bool event_pending(SCLPEventFacility *ef) SCLPEventClass *event_class; QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - event = DO_UPCAST(SCLPEvent, qdev, qdev); + event = SCLP_EVENT(kid->child); event_class = SCLP_EVENT_GET_CLASS(event); if (event->event_pending && event_class->get_send_mask() & ef->receive_mask) { From 33ee0d8e2fb5e7772a67c8785554ec9fc9477678 Mon Sep 17 00:00:00 2001 From: Antoine Damhet Date: Tue, 15 Nov 2022 15:23:28 +0100 Subject: [PATCH 718/814] crypto: TLS: introduce `check_pending` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new `qcrypto_tls_session_check_pending` function allows the caller to know if data have already been consumed from the backend and is already available. Signed-off-by: Antoine Damhet Signed-off-by: Daniel P. Berrangé --- crypto/tlssession.c | 14 ++++++++++++++ include/crypto/tlssession.h | 11 +++++++++++ 2 files changed, 25 insertions(+) diff --git a/crypto/tlssession.c b/crypto/tlssession.c index b302d835d2..1e98f44e0d 100644 --- a/crypto/tlssession.c +++ b/crypto/tlssession.c @@ -493,6 +493,13 @@ qcrypto_tls_session_read(QCryptoTLSSession *session, } +size_t +qcrypto_tls_session_check_pending(QCryptoTLSSession *session) +{ + return gnutls_record_check_pending(session->handle); +} + + int qcrypto_tls_session_handshake(QCryptoTLSSession *session, Error **errp) @@ -615,6 +622,13 @@ qcrypto_tls_session_read(QCryptoTLSSession *sess, } +size_t +qcrypto_tls_session_check_pending(QCryptoTLSSession *session) +{ + return 0; +} + + int qcrypto_tls_session_handshake(QCryptoTLSSession *sess, Error **errp) diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h index 15b9cef086..571049bd0e 100644 --- a/include/crypto/tlssession.h +++ b/include/crypto/tlssession.h @@ -248,6 +248,17 @@ ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess, char *buf, size_t len); +/** + * qcrypto_tls_session_check_pending: + * @sess: the TLS session object + * + * Check if there are unread data in the TLS buffers that have + * already been read from the underlying data source. + * + * Returns: the number of bytes available or zero + */ +size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess); + /** * qcrypto_tls_session_handshake: * @sess: the TLS session object From ffda5db65aef42266a5053a4be34515106c4c7ee Mon Sep 17 00:00:00 2001 From: Antoine Damhet Date: Tue, 15 Nov 2022 15:23:29 +0100 Subject: [PATCH 719/814] io/channel-tls: fix handling of bigger read buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the TLS backend can read more data from the underlying QIOChannel we introduce a minimal child GSource to notify if we still have more data available to be read. Signed-off-by: Antoine Damhet Signed-off-by: Charles Frey Signed-off-by: Daniel P. Berrangé --- io/channel-tls.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/io/channel-tls.c b/io/channel-tls.c index c730cb8ec5..8052945ba0 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -389,12 +389,76 @@ static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc, qio_channel_set_aio_fd_handler(tioc->master, ctx, io_read, io_write, opaque); } +typedef struct QIOChannelTLSSource QIOChannelTLSSource; +struct QIOChannelTLSSource { + GSource parent; + QIOChannelTLS *tioc; +}; + +static gboolean +qio_channel_tls_source_check(GSource *source) +{ + QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source; + + return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0; +} + +static gboolean +qio_channel_tls_source_prepare(GSource *source, gint *timeout) +{ + *timeout = -1; + return qio_channel_tls_source_check(source); +} + +static gboolean +qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback, + gpointer user_data) +{ + return G_SOURCE_CONTINUE; +} + +static void +qio_channel_tls_source_finalize(GSource *source) +{ + QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source; + + object_unref(OBJECT(tsource->tioc)); +} + +static GSourceFuncs qio_channel_tls_source_funcs = { + qio_channel_tls_source_prepare, + qio_channel_tls_source_check, + qio_channel_tls_source_dispatch, + qio_channel_tls_source_finalize +}; + +static void +qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source) +{ + GSource *child; + QIOChannelTLSSource *tlssource; + + child = g_source_new(&qio_channel_tls_source_funcs, + sizeof(QIOChannelTLSSource)); + tlssource = (QIOChannelTLSSource *)child; + + tlssource->tioc = tioc; + object_ref(OBJECT(tioc)); + + g_source_add_child_source(source, child); +} + static GSource *qio_channel_tls_create_watch(QIOChannel *ioc, GIOCondition condition) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + GSource *source = qio_channel_create_watch(tioc->master, condition); - return qio_channel_create_watch(tioc->master, condition); + if (condition & G_IO_IN) { + qio_channel_tls_read_watch(tioc, source); + } + + return source; } QCryptoTLSSession * From c3b3a6c9564bb00b0900600dc4cf965458589fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 1 Dec 2022 04:25:05 -0500 Subject: [PATCH 720/814] block: mention 'password-secret' option for -iscsi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'password-secret' option was added commit b189346eb1784df95ed6fed610411dbf23d19e1f Author: Daniel P. Berrangé Date: Thu Jan 21 14:19:21 2016 +0000 iscsi: add support for getting CHAP password via QCryptoSecret API but was not mentioned in the command line docs Reviewed-by: Markus Armbruster Reviewed-by: Fabiano Rosas Signed-off-by: Daniel P. Berrangé --- qemu-options.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 88e93c6103..e79ff4d8fb 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1892,8 +1892,8 @@ SRST ERST DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, - "-iscsi [user=user][,password=password]\n" - " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n" + "-iscsi [user=user][,password=password][,password-secret=secret-id]\n" + " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE]\n" " [,initiator-name=initiator-iqn][,id=target-iqn]\n" " [,timeout=timeout]\n" " iSCSI session parameters\n", QEMU_ARCH_ALL) From 610783cb6e47ccf0c3cde94dcb03dff2ae22107c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 1 Dec 2022 04:08:07 -0500 Subject: [PATCH 721/814] block: deprecate iSCSI 'password' in favour of 'password-secret' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for referencing secret objects was added in commit b189346eb1784df95ed6fed610411dbf23d19e1f Author: Daniel P. Berrangé Date: Thu Jan 21 14:19:21 2016 +0000 iscsi: add support for getting CHAP password via QCryptoSecret API The existing 'password' option is overdue for deprecation and subsequent removal. Reviewed-by: Fabiano Rosas Signed-off-by: Daniel P. Berrangé --- block/iscsi.c | 3 +++ docs/about/deprecated.rst | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index b3e10f40b6..ed3e87a548 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1353,6 +1353,9 @@ static void apply_chap(struct iscsi_context *iscsi, QemuOpts *opts, } else if (!password) { error_setg(errp, "CHAP username specified but no password was given"); return; + } else { + warn_report("iSCSI block driver 'password' option is deprecated, " + "use 'password-secret' instead"); } if (iscsi_set_initiator_username_pwd(iscsi, user, password)) { diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index cb1ec72347..d31ffa86d4 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -301,6 +301,14 @@ The above, converted to the current supported format:: json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"} +``iscsi,password=xxx`` (since 8.0) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specifying the iSCSI password in plain text on the command line using the +``password`` option is insecure. The ``password-secret`` option should be +used instead, to refer to a ``--object secret...`` instance that provides +a password via a file, or encrypted. + Backwards compatibility ----------------------- From 36debafddd788066be10b33c5f11b984a08e5c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 1 Dec 2022 04:22:11 -0500 Subject: [PATCH 722/814] ui: remove deprecated 'password' option for SPICE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has been replaced by the 'password-secret' option, which references a 'secret' object instance. Reviewed-by: Fabiano Rosas Reviewed-by: Markus Armbruster Signed-off-by: Daniel P. Berrangé --- docs/about/deprecated.rst | 8 -------- docs/about/removed-features.rst | 7 +++++++ qemu-options.hx | 9 +-------- ui/spice-core.c | 15 --------------- 4 files changed, 8 insertions(+), 31 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index d31ffa86d4..2827b0c0be 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -66,14 +66,6 @@ and will cause a warning. The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on`` rather than ``delay=off``. -``-spice password=string`` (since 6.0) -'''''''''''''''''''''''''''''''''''''' - -This option is insecure because the SPICE password remains visible in -the process listing. This is replaced by the new ``password-secret`` -option which lets the password be securely provided on the command -line using a ``secret`` object instance. - ``-smp`` ("parameter=0" SMP configurations) (since 6.2) ''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 4a84e6174f..e901637ce5 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -428,6 +428,13 @@ respectively. The actual backend names should be used instead. Use ``-drive if=pflash`` to configure the OTP device of the sifive_u RISC-V machine instead. +``-spice password=string`` (removed in 8.0) +''''''''''''''''''''''''''''''''''''''''''' + +This option was insecure because the SPICE password remained visible in +the process listing. This was replaced by the new ``password-secret`` +option which lets the password be securely provided on the command +line using a ``secret`` object instance. QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/qemu-options.hx b/qemu-options.hx index e79ff4d8fb..cafd8be8ed 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2135,7 +2135,7 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice, " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n" " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n" " [,sasl=on|off][,disable-ticketing=on|off]\n" - " [,password=][,password-secret=]\n" + " [,password-secret=]\n" " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n" " [,jpeg-wan-compression=[auto|never|always]]\n" " [,zlib-glz-wan-compression=[auto|never|always]]\n" @@ -2161,13 +2161,6 @@ SRST ``ipv4=on|off``; \ ``ipv6=on|off``; \ ``unix=on|off`` Force using the specified IP version. - ``password=`` - Set the password you need to authenticate. - - This option is deprecated and insecure because it leaves the - password visible in the process listing. Use ``password-secret`` - instead. - ``password-secret=`` Set the ID of the ``secret`` object containing the password you need to authenticate. diff --git a/ui/spice-core.c b/ui/spice-core.c index 72f8f1681c..76f7c2bc3d 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -412,9 +412,6 @@ static QemuOptsList qemu_spice_opts = { .name = "unix", .type = QEMU_OPT_BOOL, #endif - },{ - .name = "password", - .type = QEMU_OPT_STRING, },{ .name = "password-secret", .type = QEMU_OPT_STRING, @@ -666,20 +663,8 @@ static void qemu_spice_init(void) } passwordSecret = qemu_opt_get(opts, "password-secret"); if (passwordSecret) { - if (qemu_opt_get(opts, "password")) { - error_report("'password' option is mutually exclusive with " - "'password-secret'"); - exit(1); - } password = qcrypto_secret_lookup_as_utf8(passwordSecret, &error_fatal); - } else { - str = qemu_opt_get(opts, "password"); - if (str) { - warn_report("'password' option is deprecated and insecure, " - "use 'password-secret' instead"); - password = g_strdup(str); - } } if (tls_port) { From c7a7db4b517842633ea5ab6c848a10449b5b913a Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 9 Feb 2023 21:20:35 +0200 Subject: [PATCH 723/814] migration/qemu-file: Add qemu_file_get_to_fd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new function qemu_file_get_to_fd() that allows reading data from QEMUFile and writing it straight into a given fd. This will be used later in VFIO migration code. Signed-off-by: Avihai Horon Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/qemu-file.c | 34 ++++++++++++++++++++++++++++++++++ migration/qemu-file.h | 1 + 2 files changed, 35 insertions(+) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 2d5f74ffc2..102ab3b439 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -940,3 +940,37 @@ QIOChannel *qemu_file_get_ioc(QEMUFile *file) { return file->ioc; } + +/* + * Read size bytes from QEMUFile f and write them to fd. + */ +int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size) +{ + while (size) { + size_t pending = f->buf_size - f->buf_index; + ssize_t rc; + + if (!pending) { + rc = qemu_fill_buffer(f); + if (rc < 0) { + return rc; + } + if (rc == 0) { + return -EIO; + } + continue; + } + + rc = write(fd, f->buf + f->buf_index, MIN(pending, size)); + if (rc < 0) { + return -errno; + } + if (rc == 0) { + return -EIO; + } + f->buf_index += rc; + size -= rc; + } + + return 0; +} diff --git a/migration/qemu-file.h b/migration/qemu-file.h index fa13d04d78..9d0155a2a1 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -148,6 +148,7 @@ int qemu_file_shutdown(QEMUFile *f); QEMUFile *qemu_file_get_return_path(QEMUFile *f); void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); +int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size); void ram_control_before_iterate(QEMUFile *f, uint64_t flags); void ram_control_after_iterate(QEMUFile *f, uint64_t flags); From 163b8663b87fa1bfc34a171dd19ea435d108fa61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 15 Feb 2023 16:35:17 +0100 Subject: [PATCH 724/814] migration/block: Convert remaining DPRINTF() debug macro to trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finish the conversion from commit fe80c0241d ("migration: using trace_ to replace DPRINTF"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/block.c | 12 +----------- migration/trace-events | 1 + 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/migration/block.c b/migration/block.c index 29f69025af..b5ce506d01 100644 --- a/migration/block.c +++ b/migration/block.c @@ -42,16 +42,6 @@ #define MAX_IO_BUFFERS 512 #define MAX_PARALLEL_IO 16 -/* #define DEBUG_BLK_MIGRATION */ - -#ifdef DEBUG_BLK_MIGRATION -#define DPRINTF(fmt, ...) \ - do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - typedef struct BlkMigDevState { /* Written during setup phase. Can be read without a lock. */ BlockBackend *blk; @@ -502,7 +492,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f) block_mig_state.prev_progress = progress; qemu_put_be64(f, (progress << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); - DPRINTF("Completed %d %%\r", progress); + trace_migration_block_progression(progress); } return ret; diff --git a/migration/trace-events b/migration/trace-events index 67b65a70ff..b20e1271bc 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -357,6 +357,7 @@ migration_block_flush_blks(const char *action, int submitted, int read_done, int migration_block_save(const char *mig_stage, int submitted, int transferred) "Enter save live %s submitted %d transferred %d" migration_block_save_complete(void) "Block migration completed" migration_block_state_pending(uint64_t pending) "Enter save live pending %" PRIu64 +migration_block_progression(unsigned percent) "Completed %u%%" # page_cache.c migration_pagecache_init(int64_t max_num_items) "Setting cache buckets to %" PRId64 From abbbd04da2b2bdda5ee7dcbbbc89e03e019ade6b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 8 Feb 2023 14:34:24 +0100 Subject: [PATCH 725/814] migration: In case of postcopy, the memory ends in res_postcopy_only So remove last assignation of res_compatible. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Juan Quintela --- migration/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index 521912385d..ecf697a58d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3528,7 +3528,7 @@ static void ram_state_pending_exact(void *opaque, if (migrate_postcopy_ram()) { /* We can do postcopy, and all the data is postcopiable */ - *res_compatible += remaining_size; + *res_postcopy_only += remaining_size; } else { *res_precopy_only += remaining_size; } From 24f254ed794bbd217fbceb6b5840dd4fa6545383 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 8 Feb 2023 14:41:06 +0100 Subject: [PATCH 726/814] migration: Remove unused res_compatible Nothing assigns to it after previous commit. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Juan Quintela --- hw/s390x/s390-stattrib.c | 1 - hw/vfio/migration.c | 3 +-- hw/vfio/trace-events | 2 +- include/migration/register.h | 7 ++----- migration/block-dirty-bitmap.c | 1 - migration/block.c | 1 - migration/migration.c | 18 ++++++++---------- migration/ram.c | 2 -- migration/savevm.c | 8 ++------ migration/savevm.h | 2 -- migration/trace-events | 4 ++-- 11 files changed, 16 insertions(+), 33 deletions(-) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 3e32002eab..c7ae9184ab 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -184,7 +184,6 @@ static int cmma_save_setup(QEMUFile *f, void *opaque) static void cmma_state_pending(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { S390StAttribState *sas = S390_STATTRIB(opaque); diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index b3318f0f20..fb0dd9571d 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -458,7 +458,6 @@ static void vfio_save_cleanup(void *opaque) static void vfio_state_pending(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { VFIODevice *vbasedev = opaque; @@ -473,7 +472,7 @@ static void vfio_state_pending(void *opaque, *res_precopy_only += migration->pending_bytes; trace_vfio_state_pending(vbasedev->name, *res_precopy_only, - *res_postcopy_only, *res_compatible); + *res_postcopy_only); } static int vfio_save_iterate(QEMUFile *f, void *opaque) diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 52de1c84f8..90a8aecb37 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -157,7 +157,7 @@ vfio_save_cleanup(const char *name) " (%s)" vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 vfio_save_device_config_state(const char *name) " (%s)" -vfio_state_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 +vfio_state_pending(const char *name, uint64_t precopy, uint64_t postcopy) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64 vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" vfio_save_complete_precopy(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" diff --git a/include/migration/register.h b/include/migration/register.h index b91a0cdbf8..a958a92a0f 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -49,22 +49,19 @@ typedef struct SaveVMHandlers { /* Note for save_live_pending: * - res_precopy_only is for data which must be migrated in precopy phase * or in stopped state, in other words - before target vm start - * - res_compatible is for data which may be migrated in any phase * - res_postcopy_only is for data which must be migrated in postcopy phase * or in stopped state, in other words - after source vm stop * - * Sum of res_postcopy_only, res_compatible and res_postcopy_only is the - * whole amount of pending data. + * Sum of res_postcopy_only and res_postcopy_only is the whole + * amount of pending data. */ /* This estimates the remaining data to transfer */ void (*state_pending_estimate)(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only); /* This calculate the exact remaining data to transfer */ void (*state_pending_exact)(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only); LoadStateHandler *load_state; int (*load_setup)(QEMUFile *f, void *opaque); diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 5a621419d3..9c6655e11a 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -764,7 +764,6 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) static void dirty_bitmap_state_pending(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { DBMSaveState *s = &((DBMState *)opaque)->save; diff --git a/migration/block.c b/migration/block.c index b5ce506d01..168ef89a82 100644 --- a/migration/block.c +++ b/migration/block.c @@ -855,7 +855,6 @@ static int block_save_complete(QEMUFile *f, void *opaque) static void block_state_pending(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { /* Estimate pending number of bytes to send */ diff --git a/migration/migration.c b/migration/migration.c index 90fca70cb7..296f7fe768 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3863,20 +3863,18 @@ typedef enum { */ static MigIterateState migration_iteration_run(MigrationState *s) { - uint64_t pend_pre, pend_compat, pend_post; + uint64_t pend_pre, pend_post; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; - qemu_savevm_state_pending_estimate(&pend_pre, &pend_compat, &pend_post); - uint64_t pending_size = pend_pre + pend_compat + pend_post; + qemu_savevm_state_pending_estimate(&pend_pre, &pend_post); + uint64_t pending_size = pend_pre + pend_post; - trace_migrate_pending_estimate(pending_size, - pend_pre, pend_compat, pend_post); + trace_migrate_pending_estimate(pending_size, pend_pre, pend_post); - if (pend_pre + pend_compat <= s->threshold_size) { - qemu_savevm_state_pending_exact(&pend_pre, &pend_compat, &pend_post); - pending_size = pend_pre + pend_compat + pend_post; - trace_migrate_pending_exact(pending_size, - pend_pre, pend_compat, pend_post); + if (pend_pre <= s->threshold_size) { + qemu_savevm_state_pending_exact(&pend_pre, &pend_post); + pending_size = pend_pre + pend_post; + trace_migrate_pending_exact(pending_size, pend_pre, pend_post); } if (!pending_size || pending_size < s->threshold_size) { diff --git a/migration/ram.c b/migration/ram.c index ecf697a58d..178f92a77f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3491,7 +3491,6 @@ static int ram_save_complete(QEMUFile *f, void *opaque) static void ram_state_pending_estimate(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { RAMState **temp = opaque; @@ -3509,7 +3508,6 @@ static void ram_state_pending_estimate(void *opaque, static void ram_state_pending_exact(void *opaque, uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { RAMState **temp = opaque; diff --git a/migration/savevm.c b/migration/savevm.c index b5e6962bb6..80b7f1222a 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1542,13 +1542,11 @@ flush: * for units that can't do postcopy. */ void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { SaveStateEntry *se; *res_precopy_only = 0; - *res_compatible = 0; *res_postcopy_only = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { @@ -1561,19 +1559,17 @@ void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, } } se->ops->state_pending_estimate(se->opaque, - res_precopy_only, res_compatible, + res_precopy_only, res_postcopy_only); } } void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only) { SaveStateEntry *se; *res_precopy_only = 0; - *res_compatible = 0; *res_postcopy_only = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { @@ -1586,7 +1582,7 @@ void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, } } se->ops->state_pending_exact(se->opaque, - res_precopy_only, res_compatible, + res_precopy_only, res_postcopy_only); } } diff --git a/migration/savevm.h b/migration/savevm.h index b1901e68d5..bd625a644b 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -41,10 +41,8 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f); int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, bool inactivate_disks); void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only); void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, - uint64_t *res_compatible, uint64_t *res_postcopy_only); void qemu_savevm_send_ping(QEMUFile *f, uint32_t value); void qemu_savevm_send_open_return_path(QEMUFile *f); diff --git a/migration/trace-events b/migration/trace-events index b20e1271bc..92161eeac5 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -150,8 +150,8 @@ migrate_fd_cleanup(void) "" migrate_fd_error(const char *error_desc) "error=%s" migrate_fd_cancel(void) "" migrate_handle_rp_req_pages(const char *rbname, size_t start, size_t len) "in %s at 0x%zx len 0x%zx" -migrate_pending_exact(uint64_t size, uint64_t pre, uint64_t compat, uint64_t post) "exact pending size %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" -migrate_pending_estimate(uint64_t size, uint64_t pre, uint64_t compat, uint64_t post) "estimate pending size %" PRIu64 " (pre = %" PRIu64 " compat=%" PRIu64 " post=%" PRIu64 ")" +migrate_pending_exact(uint64_t size, uint64_t pre, uint64_t post) "exact pending size %" PRIu64 " (pre = %" PRIu64 " post=%" PRIu64 ")" +migrate_pending_estimate(uint64_t size, uint64_t pre, uint64_t post) "estimate pending size %" PRIu64 " (pre = %" PRIu64 " post=%" PRIu64 ")" migrate_send_rp_message(int msg_type, uint16_t len) "%d: len %d" migrate_send_rp_recv_bitmap(char *name, int64_t size) "block '%s' size 0x%"PRIi64 migration_completion_file_err(void) "" From 24beea4efe6e6b65fd6248ede936cd3278b2bf8a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 8 Feb 2023 14:48:02 +0100 Subject: [PATCH 727/814] migration: Rename res_{postcopy,precopy}_only Once that res_compatible is removed, they don't make sense anymore. We remove the _only preffix. And to make things clearer we rename them to must_precopy and can_postcopy. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Juan Quintela --- hw/s390x/s390-stattrib.c | 7 +++---- hw/vfio/migration.c | 10 ++++------ include/migration/register.h | 27 +++++++++++++++------------ migration/block-dirty-bitmap.c | 6 +++--- migration/block.c | 7 +++---- migration/migration.c | 18 +++++++++--------- migration/ram.c | 18 ++++++++---------- migration/savevm.c | 24 ++++++++++-------------- migration/savevm.h | 8 ++++---- 9 files changed, 59 insertions(+), 66 deletions(-) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index c7ae9184ab..aed919ad7d 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -182,16 +182,15 @@ static int cmma_save_setup(QEMUFile *f, void *opaque) return 0; } -static void cmma_state_pending(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +static void cmma_state_pending(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { S390StAttribState *sas = S390_STATTRIB(opaque); S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); long long res = sac->get_dirtycount(sas); if (res >= 0) { - *res_precopy_only += res; + *must_precopy += res; } } diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index fb0dd9571d..83d2d44080 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -456,9 +456,8 @@ static void vfio_save_cleanup(void *opaque) trace_vfio_save_cleanup(vbasedev->name); } -static void vfio_state_pending(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +static void vfio_state_pending(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; @@ -469,10 +468,9 @@ static void vfio_state_pending(void *opaque, return; } - *res_precopy_only += migration->pending_bytes; + *must_precopy += migration->pending_bytes; - trace_vfio_state_pending(vbasedev->name, *res_precopy_only, - *res_postcopy_only); + trace_vfio_state_pending(vbasedev->name, *must_precopy, *can_postcopy); } static int vfio_save_iterate(QEMUFile *f, void *opaque) diff --git a/include/migration/register.h b/include/migration/register.h index a958a92a0f..a8dfd8fefd 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -47,22 +47,25 @@ typedef struct SaveVMHandlers { /* This runs outside the iothread lock! */ int (*save_setup)(QEMUFile *f, void *opaque); /* Note for save_live_pending: - * - res_precopy_only is for data which must be migrated in precopy phase - * or in stopped state, in other words - before target vm start - * - res_postcopy_only is for data which must be migrated in postcopy phase - * or in stopped state, in other words - after source vm stop + * must_precopy: + * - must be migrated in precopy or in stopped state + * - i.e. must be migrated before target start * - * Sum of res_postcopy_only and res_postcopy_only is the whole - * amount of pending data. + * can_postcopy: + * - can migrate in postcopy or in stopped state + * - i.e. can migrate after target start + * - some can also be migrated during precopy (RAM) + * - some must be migrated after source stops (block-dirty-bitmap) + * + * Sum of can_postcopy and must_postcopy is the whole amount of + * pending data. */ /* This estimates the remaining data to transfer */ - void (*state_pending_estimate)(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only); + void (*state_pending_estimate)(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy); /* This calculate the exact remaining data to transfer */ - void (*state_pending_exact)(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only); + void (*state_pending_exact)(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy); LoadStateHandler *load_state; int (*load_setup)(QEMUFile *f, void *opaque); int (*load_cleanup)(void *opaque); diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 9c6655e11a..fe73aa94b1 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -763,8 +763,8 @@ static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque) } static void dirty_bitmap_state_pending(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) + uint64_t *must_precopy, + uint64_t *can_postcopy) { DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms; @@ -784,7 +784,7 @@ static void dirty_bitmap_state_pending(void *opaque, trace_dirty_bitmap_state_pending(pending); - *res_postcopy_only += pending; + *can_postcopy += pending; } /* First occurrence of this bitmap. It should be created if doesn't exist */ diff --git a/migration/block.c b/migration/block.c index 168ef89a82..426a25bb19 100644 --- a/migration/block.c +++ b/migration/block.c @@ -853,9 +853,8 @@ static int block_save_complete(QEMUFile *f, void *opaque) return 0; } -static void block_state_pending(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +static void block_state_pending(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { /* Estimate pending number of bytes to send */ uint64_t pending; @@ -876,7 +875,7 @@ static void block_state_pending(void *opaque, trace_migration_block_state_pending(pending); /* We don't do postcopy */ - *res_precopy_only += pending; + *must_precopy += pending; } static int block_load(QEMUFile *f, void *opaque, int version_id) diff --git a/migration/migration.c b/migration/migration.c index 296f7fe768..ae2025d9d8 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3863,18 +3863,18 @@ typedef enum { */ static MigIterateState migration_iteration_run(MigrationState *s) { - uint64_t pend_pre, pend_post; + uint64_t must_precopy, can_postcopy; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; - qemu_savevm_state_pending_estimate(&pend_pre, &pend_post); - uint64_t pending_size = pend_pre + pend_post; + qemu_savevm_state_pending_estimate(&must_precopy, &can_postcopy); + uint64_t pending_size = must_precopy + can_postcopy; - trace_migrate_pending_estimate(pending_size, pend_pre, pend_post); + trace_migrate_pending_estimate(pending_size, must_precopy, can_postcopy); - if (pend_pre <= s->threshold_size) { - qemu_savevm_state_pending_exact(&pend_pre, &pend_post); - pending_size = pend_pre + pend_post; - trace_migrate_pending_exact(pending_size, pend_pre, pend_post); + if (must_precopy <= s->threshold_size) { + qemu_savevm_state_pending_exact(&must_precopy, &can_postcopy); + pending_size = must_precopy + can_postcopy; + trace_migrate_pending_exact(pending_size, must_precopy, can_postcopy); } if (!pending_size || pending_size < s->threshold_size) { @@ -3884,7 +3884,7 @@ static MigIterateState migration_iteration_run(MigrationState *s) } /* Still a significant amount to transfer */ - if (!in_postcopy && pend_pre <= s->threshold_size && + if (!in_postcopy && must_precopy <= s->threshold_size && qatomic_read(&s->start_postcopy)) { if (postcopy_start(s)) { error_report("%s: postcopy failed to start", __func__); diff --git a/migration/ram.c b/migration/ram.c index 178f92a77f..96e8a19a58 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3489,9 +3489,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque) return 0; } -static void ram_state_pending_estimate(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +static void ram_state_pending_estimate(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { RAMState **temp = opaque; RAMState *rs = *temp; @@ -3500,15 +3499,14 @@ static void ram_state_pending_estimate(void *opaque, if (migrate_postcopy_ram()) { /* We can do postcopy, and all the data is postcopiable */ - *res_postcopy_only += remaining_size; + *can_postcopy += remaining_size; } else { - *res_precopy_only += remaining_size; + *must_precopy += remaining_size; } } -static void ram_state_pending_exact(void *opaque, - uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +static void ram_state_pending_exact(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { RAMState **temp = opaque; RAMState *rs = *temp; @@ -3526,9 +3524,9 @@ static void ram_state_pending_exact(void *opaque, if (migrate_postcopy_ram()) { /* We can do postcopy, and all the data is postcopiable */ - *res_postcopy_only += remaining_size; + *can_postcopy += remaining_size; } else { - *res_precopy_only += remaining_size; + *must_precopy += remaining_size; } } diff --git a/migration/savevm.c b/migration/savevm.c index 80b7f1222a..aa54a67fda 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1541,13 +1541,13 @@ flush: * the result is split into the amount for units that can and * for units that can't do postcopy. */ -void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +void qemu_savevm_state_pending_estimate(uint64_t *must_precopy, + uint64_t *can_postcopy) { SaveStateEntry *se; - *res_precopy_only = 0; - *res_postcopy_only = 0; + *must_precopy = 0; + *can_postcopy = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || !se->ops->state_pending_estimate) { @@ -1558,19 +1558,17 @@ void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, continue; } } - se->ops->state_pending_estimate(se->opaque, - res_precopy_only, - res_postcopy_only); + se->ops->state_pending_estimate(se->opaque, must_precopy, can_postcopy); } } -void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, - uint64_t *res_postcopy_only) +void qemu_savevm_state_pending_exact(uint64_t *must_precopy, + uint64_t *can_postcopy) { SaveStateEntry *se; - *res_precopy_only = 0; - *res_postcopy_only = 0; + *must_precopy = 0; + *can_postcopy = 0; QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || !se->ops->state_pending_exact) { @@ -1581,9 +1579,7 @@ void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, continue; } } - se->ops->state_pending_exact(se->opaque, - res_precopy_only, - res_postcopy_only); + se->ops->state_pending_exact(se->opaque, must_precopy, can_postcopy); } } diff --git a/migration/savevm.h b/migration/savevm.h index bd625a644b..fb636735f0 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -40,10 +40,10 @@ void qemu_savevm_state_cleanup(void); void qemu_savevm_state_complete_postcopy(QEMUFile *f); int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, bool inactivate_disks); -void qemu_savevm_state_pending_exact(uint64_t *res_precopy_only, - uint64_t *res_postcopy_only); -void qemu_savevm_state_pending_estimate(uint64_t *res_precopy_only, - uint64_t *res_postcopy_only); +void qemu_savevm_state_pending_exact(uint64_t *must_precopy, + uint64_t *can_postcopy); +void qemu_savevm_state_pending_estimate(uint64_t *must_precopy, + uint64_t *can_postcopy); 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 9b772b19fcccbd3d7ed12e69f272db16d023c82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:52 +0100 Subject: [PATCH 728/814] hw/intc/armv7m_nvic: Use OBJECT_DECLARE_SIMPLE_TYPE() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manually convert to OBJECT_DECLARE_SIMPLE_TYPE() macro, similarly to automatic conversion from commit 8063396bf3 ("Use OBJECT_DECLARE_SIMPLE_TYPE when possible"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230206223502.25122-2-philmd@linaro.org Signed-off-by: Peter Maydell --- include/hw/intc/armv7m_nvic.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h index 0180c7b0ca..07f9c21a5f 100644 --- a/include/hw/intc/armv7m_nvic.h +++ b/include/hw/intc/armv7m_nvic.h @@ -16,10 +16,7 @@ #include "qom/object.h" #define TYPE_NVIC "armv7m_nvic" - -typedef struct NVICState NVICState; -DECLARE_INSTANCE_CHECKER(NVICState, NVIC, - TYPE_NVIC) +OBJECT_DECLARE_SIMPLE_TYPE(NVICState, NVIC) /* Highest permitted number of exceptions (architectural limit) */ #define NVIC_MAX_VECTORS 512 From 1eb13a0947e9ef1b2ca2a3396eb661a3b22b45d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:53 +0100 Subject: [PATCH 729/814] target/arm: Simplify arm_v7m_mmu_idx_for_secstate() for user emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230206223502.25122-3-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/m_helper.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index e7e746ea18..76239c9abe 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -150,7 +150,12 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) return 0; } -#else +ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) +{ + return ARMMMUIdx_MUser; +} + +#else /* !CONFIG_USER_ONLY */ /* * What kind of stack write are we doing? This affects how exceptions @@ -2854,8 +2859,6 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) return tt_resp; } -#endif /* !CONFIG_USER_ONLY */ - ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, bool secstate, bool priv, bool negpri) { @@ -2892,3 +2895,5 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); } + +#endif /* !CONFIG_USER_ONLY */ From eda349be62d2c7441d9dfd5ca62b5af4db919e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:54 +0100 Subject: [PATCH 730/814] target/arm: Reduce arm_v7m_mmu_idx_[all/for_secstate_and_priv]() scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_v7m_mmu_idx_all() and arm_v7m_mmu_idx_for_secstate_and_priv() are only used for system emulation in m_helper.c. Move the definitions to avoid prototype forward declarations. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230206223502.25122-4-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 14 -------- target/arm/m_helper.c | 74 +++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index e1e018da46..759b70c646 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -597,20 +597,6 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx) int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx); -/* - * Return the MMU index for a v7M CPU with all relevant information - * manually specified. - */ -ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, - bool secstate, bool priv, bool negpri); - -/* - * Return the MMU index for a v7M CPU in the specified security and - * privilege state. - */ -ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, - bool secstate, bool priv); - /* Return the MMU index for a v7M CPU in the specified security state */ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate); diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 76239c9abe..b4964dca8a 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -157,6 +157,43 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) #else /* !CONFIG_USER_ONLY */ +static ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, + bool secstate, bool priv, bool negpri) +{ + ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; + + if (priv) { + mmu_idx |= ARM_MMU_IDX_M_PRIV; + } + + if (negpri) { + mmu_idx |= ARM_MMU_IDX_M_NEGPRI; + } + + if (secstate) { + mmu_idx |= ARM_MMU_IDX_M_S; + } + + return mmu_idx; +} + +static ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, + bool secstate, bool priv) +{ + bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate); + + return arm_v7m_mmu_idx_all(env, secstate, priv, negpri); +} + +/* Return the MMU index for a v7M CPU in the specified security state */ +ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) +{ + bool priv = arm_v7m_is_handler_mode(env) || + !(env->v7m.control[secstate] & 1); + + return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); +} + /* * What kind of stack write are we doing? This affects how exceptions * generated during the stacking are treated. @@ -2859,41 +2896,4 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) return tt_resp; } -ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env, - bool secstate, bool priv, bool negpri) -{ - ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; - - if (priv) { - mmu_idx |= ARM_MMU_IDX_M_PRIV; - } - - if (negpri) { - mmu_idx |= ARM_MMU_IDX_M_NEGPRI; - } - - if (secstate) { - mmu_idx |= ARM_MMU_IDX_M_S; - } - - return mmu_idx; -} - -ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, - bool secstate, bool priv) -{ - bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate); - - return arm_v7m_mmu_idx_all(env, secstate, priv, negpri); -} - -/* Return the MMU index for a v7M CPU in the specified security state */ -ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) -{ - bool priv = arm_v7m_is_handler_mode(env) || - !(env->v7m.control[secstate] & 1); - - return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); -} - #endif /* !CONFIG_USER_ONLY */ From 0f150c8499e970bd079a80394ccf65bcd7a54f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:55 +0100 Subject: [PATCH 731/814] target/arm: Constify ID_PFR1 on user emulation 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: 20230206223502.25122-5-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c62ed05c12..22670c20c0 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7021,6 +7021,7 @@ static void define_pmu_regs(ARMCPU *cpu) } } +#ifndef CONFIG_USER_ONLY /* * We don't know until after realize whether there's a GICv3 * attached, and that is what registers the gicv3 sysregs. @@ -7038,7 +7039,6 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) return pfr1; } -#ifndef CONFIG_USER_ONLY static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = env_archcpu(env); @@ -7998,8 +7998,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 1, .access = PL1_R, .type = ARM_CP_NO_RAW, .accessfn = access_aa32_tid3, +#ifdef CONFIG_USER_ONLY + .type = ARM_CP_CONST, + .resetvalue = cpu->isar.id_pfr1, +#else + .type = ARM_CP_NO_RAW, + .accessfn = access_aa32_tid3, .readfn = id_pfr1_read, - .writefn = arm_cp_write_ignore }, + .writefn = arm_cp_write_ignore +#endif + }, { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, From de4143fc77fd33a01b651cd00fb4f20b65de359b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:56 +0100 Subject: [PATCH 732/814] target/arm: Convert CPUARMState::eabi to boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230206223502.25122-6-philmd@linaro.org Signed-off-by: Peter Maydell --- linux-user/arm/cpu_loop.c | 4 ++-- linux-user/user-internals.h | 2 +- target/arm/cpu.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index c0790f3246..a992423257 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -356,7 +356,7 @@ void cpu_loop(CPUARMState *env) break; case EXCP_SWI: { - env->eabi = 1; + env->eabi = true; /* system call */ if (env->thumb) { /* Thumb is always EABI style with syscall number in r7 */ @@ -382,7 +382,7 @@ void cpu_loop(CPUARMState *env) * > 0xfffff and are handled below as out-of-range. */ n ^= ARM_SYSCALL_BASE; - env->eabi = 0; + env->eabi = false; } } diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 0280e76add..3576da413f 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -135,7 +135,7 @@ void print_termios(void *arg); #ifdef TARGET_ARM static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { - return cpu_env->eabi == 1; + return cpu_env->eabi; } #elif defined(TARGET_MIPS) && defined(TARGET_ABI_MIPSO32) static inline int regpairs_aligned(CPUArchState *cpu_env, int num) { return 1; } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 7bc97fece9..05b9012cee 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -723,7 +723,7 @@ typedef struct CPUArchState { #if defined(CONFIG_USER_ONLY) /* For usermode syscall translation. */ - int eabi; + bool eabi; #endif struct CPUBreakpoint *cpu_breakpoint[16]; From 26f08561302fdc1ba18212a5812db2f48ec9eb7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:57 +0100 Subject: [PATCH 733/814] target/arm: Avoid resetting CPUARMState::eabi field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the 'eabi' field is only used in user emulation where CPU reset doesn't occur, it doesn't belong to the area to reset. Move it after the 'end_reset_fields' for consistency. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230206223502.25122-7-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 05b9012cee..1c1e0334f0 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -721,11 +721,6 @@ typedef struct CPUArchState { ARMVectorReg zarray[ARM_MAX_VQ * 16]; #endif -#if defined(CONFIG_USER_ONLY) - /* For usermode syscall translation. */ - bool eabi; -#endif - struct CPUBreakpoint *cpu_breakpoint[16]; struct CPUWatchpoint *cpu_watchpoint[16]; @@ -776,6 +771,10 @@ typedef struct CPUArchState { const struct arm_boot_info *boot_info; /* Store GICv3CPUState to access from this struct */ void *gicv3state; +#if defined(CONFIG_USER_ONLY) + /* For usermode syscall translation. */ + bool eabi; +#endif /* CONFIG_USER_ONLY */ #ifdef TARGET_TAGGED_ADDRESSES /* Linux syscall tagged address support */ From 1701d70e15ef7337f467d1daaecee8f6d17535aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:58 +0100 Subject: [PATCH 734/814] target/arm: Restrict CPUARMState::gicv3state to sysemu 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: 20230206223502.25122-8-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 1c1e0334f0..002082eb5b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -769,9 +769,10 @@ typedef struct CPUArchState { void *nvic; const struct arm_boot_info *boot_info; +#if !defined(CONFIG_USER_ONLY) /* Store GICv3CPUState to access from this struct */ void *gicv3state; -#if defined(CONFIG_USER_ONLY) +#else /* CONFIG_USER_ONLY */ /* For usermode syscall translation. */ bool eabi; #endif /* CONFIG_USER_ONLY */ From 2a94a5077637648e05b8bf3b342dadf52a4f1f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:34:59 +0100 Subject: [PATCH 735/814] target/arm: Restrict CPUARMState::arm_boot_info to sysemu 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: 20230206223502.25122-9-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 002082eb5b..a574e85b76 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -768,8 +768,8 @@ typedef struct CPUArchState { } sau; void *nvic; - const struct arm_boot_info *boot_info; #if !defined(CONFIG_USER_ONLY) + const struct arm_boot_info *boot_info; /* Store GICv3CPUState to access from this struct */ void *gicv3state; #else /* CONFIG_USER_ONLY */ From 2bd6918f3cfe939c1335f421da2cae0221cf28e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:35:00 +0100 Subject: [PATCH 736/814] target/arm: Restrict CPUARMState::nvic to sysemu 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: 20230206223502.25122-10-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a574e85b76..01f9566a1b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -767,8 +767,8 @@ typedef struct CPUArchState { uint32_t ctrl; } sau; - void *nvic; #if !defined(CONFIG_USER_ONLY) + void *nvic; const struct arm_boot_info *boot_info; /* Store GICv3CPUState to access from this struct */ void *gicv3state; From 8f4e07c9d1e8cf58ab196148e0c179e95f70201e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:35:01 +0100 Subject: [PATCH 737/814] target/arm: Store CPUARMState::nvic as NVICState* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no point in using a void pointer to access the NVIC. Use the real type to avoid casting it while debugging. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20230206223502.25122-11-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 38 ++++++++++++----------------------- target/arm/cpu.c | 1 + target/arm/cpu.h | 46 ++++++++++++++++++++++--------------------- target/arm/m_helper.c | 2 +- 4 files changed, 39 insertions(+), 48 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 1f7763964c..e54553283f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -389,7 +389,7 @@ static inline int nvic_exec_prio(NVICState *s) return MIN(running, s->exception_prio); } -bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) +bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure) { /* Return true if the requested execution priority is negative * for the specified security state, ie that security state @@ -399,8 +399,6 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) * mean we don't allow FAULTMASK_NS to actually make the execution * priority negative). Compare pseudocode IsReqExcPriNeg(). */ - NVICState *s = opaque; - if (s->cpu->env.v7m.faultmask[secure]) { return true; } @@ -418,17 +416,13 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) return false; } -bool armv7m_nvic_can_take_pending_exception(void *opaque) +bool armv7m_nvic_can_take_pending_exception(NVICState *s) { - NVICState *s = opaque; - return nvic_exec_prio(s) > nvic_pending_prio(s); } -int armv7m_nvic_raw_execution_priority(void *opaque) +int armv7m_nvic_raw_execution_priority(NVICState *s) { - NVICState *s = opaque; - return s->exception_prio; } @@ -506,9 +500,8 @@ static void nvic_irq_update(NVICState *s) * if @secure is true and @irq does not specify one of the fixed set * of architecturally banked exceptions. */ -static void armv7m_nvic_clear_pending(void *opaque, int irq, bool secure) +static void armv7m_nvic_clear_pending(NVICState *s, int irq, bool secure) { - NVICState *s = (NVICState *)opaque; VecInfo *vec; assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq); @@ -666,17 +659,17 @@ static void do_armv7m_nvic_set_pending(void *opaque, int irq, bool secure, } } -void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) +void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure) { - do_armv7m_nvic_set_pending(opaque, irq, secure, false); + do_armv7m_nvic_set_pending(s, irq, secure, false); } -void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure) +void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure) { - do_armv7m_nvic_set_pending(opaque, irq, secure, true); + do_armv7m_nvic_set_pending(s, irq, secure, true); } -void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure) +void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure) { /* * Pend an exception during lazy FP stacking. This differs @@ -684,7 +677,6 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure) * whether we should escalate depends on the saved context * in the FPCCR register, not on the current state of the CPU/NVIC. */ - NVICState *s = (NVICState *)opaque; bool banked = exc_is_banked(irq); VecInfo *vec; bool targets_secure; @@ -773,9 +765,8 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure) } /* Make pending IRQ active. */ -void armv7m_nvic_acknowledge_irq(void *opaque) +void armv7m_nvic_acknowledge_irq(NVICState *s) { - NVICState *s = (NVICState *)opaque; CPUARMState *env = &s->cpu->env; const int pending = s->vectpending; const int running = nvic_exec_prio(s); @@ -814,10 +805,9 @@ static bool vectpending_targets_secure(NVICState *s) exc_targets_secure(s, s->vectpending); } -void armv7m_nvic_get_pending_irq_info(void *opaque, +void armv7m_nvic_get_pending_irq_info(NVICState *s, int *pirq, bool *ptargets_secure) { - NVICState *s = (NVICState *)opaque; const int pending = s->vectpending; bool targets_secure; @@ -831,9 +821,8 @@ void armv7m_nvic_get_pending_irq_info(void *opaque, *pirq = pending; } -int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) +int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure) { - NVICState *s = (NVICState *)opaque; VecInfo *vec = NULL; int ret = 0; @@ -915,7 +904,7 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) return ret; } -bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) +bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure) { /* * Return whether an exception is "ready", i.e. it is enabled and is @@ -926,7 +915,6 @@ bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) * for non-banked exceptions secure is always false; for banked exceptions * it indicates which of the exceptions is required. */ - NVICState *s = (NVICState *)opaque; bool banked = exc_is_banked(irq); VecInfo *vec; int running = nvic_exec_prio(s); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5f63316dbf..b3a2275b08 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -36,6 +36,7 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/loader.h" #include "hw/boards.h" +#include "hw/intc/armv7m_nvic.h" #endif #include "sysemu/tcg.h" #include "sysemu/qtest.h" diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 01f9566a1b..9a80819d8d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -227,6 +227,8 @@ typedef struct CPUARMTBFlags { typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; +typedef struct NVICState NVICState; + typedef struct CPUArchState { /* Regs for current mode. */ uint32_t regs[16]; @@ -768,7 +770,7 @@ typedef struct CPUArchState { } sau; #if !defined(CONFIG_USER_ONLY) - void *nvic; + NVICState *nvic; const struct arm_boot_info *boot_info; /* Store GICv3CPUState to access from this struct */ void *gicv3state; @@ -2559,16 +2561,16 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, /* Interface between CPU and Interrupt controller. */ #ifndef CONFIG_USER_ONLY -bool armv7m_nvic_can_take_pending_exception(void *opaque); +bool armv7m_nvic_can_take_pending_exception(NVICState *s); #else -static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) +static inline bool armv7m_nvic_can_take_pending_exception(NVICState *s) { return true; } #endif /** * armv7m_nvic_set_pending: mark the specified exception as pending - * @opaque: the NVIC + * @s: the NVIC * @irq: the exception number to mark pending * @secure: false for non-banked exceptions or for the nonsecure * version of a banked exception, true for the secure version of a banked @@ -2578,10 +2580,10 @@ static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) * if @secure is true and @irq does not specify one of the fixed set * of architecturally banked exceptions. */ -void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); +void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure); /** * armv7m_nvic_set_pending_derived: mark this derived exception as pending - * @opaque: the NVIC + * @s: the NVIC * @irq: the exception number to mark pending * @secure: false for non-banked exceptions or for the nonsecure * version of a banked exception, true for the secure version of a banked @@ -2591,10 +2593,10 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); * exceptions (exceptions generated in the course of trying to take * a different exception). */ -void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); +void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure); /** * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending - * @opaque: the NVIC + * @s: the NVIC * @irq: the exception number to mark pending * @secure: false for non-banked exceptions or for the nonsecure * version of a banked exception, true for the secure version of a banked @@ -2603,11 +2605,11 @@ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); * Similar to armv7m_nvic_set_pending(), but specifically for exceptions * generated in the course of lazy stacking of FP registers. */ -void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure); +void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure); /** * armv7m_nvic_get_pending_irq_info: return highest priority pending * exception, and whether it targets Secure state - * @opaque: the NVIC + * @s: the NVIC * @pirq: set to pending exception number * @ptargets_secure: set to whether pending exception targets Secure * @@ -2617,20 +2619,20 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure); * to true if the current highest priority pending exception should * be taken to Secure state, false for NS. */ -void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, +void armv7m_nvic_get_pending_irq_info(NVICState *s, int *pirq, bool *ptargets_secure); /** * armv7m_nvic_acknowledge_irq: make highest priority pending exception active - * @opaque: the NVIC + * @s: the NVIC * * Move the current highest priority pending exception from the pending * state to the active state, and update v7m.exception to indicate that * it is the exception currently being handled. */ -void armv7m_nvic_acknowledge_irq(void *opaque); +void armv7m_nvic_acknowledge_irq(NVICState *s); /** * armv7m_nvic_complete_irq: complete specified interrupt or exception - * @opaque: the NVIC + * @s: the NVIC * @irq: the exception number to complete * @secure: true if this exception was secure * @@ -2639,10 +2641,10 @@ void armv7m_nvic_acknowledge_irq(void *opaque); * 0 if there is still an irq active after this one was completed * (Ignoring -1, this is the same as the RETTOBASE value before completion.) */ -int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); +int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure); /** * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) - * @opaque: the NVIC + * @s: the NVIC * @irq: the exception number to mark pending * @secure: false for non-banked exceptions or for the nonsecure * version of a banked exception, true for the secure version of a banked @@ -2653,28 +2655,28 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); * interrupt the current execution priority. This controls whether the * RDY bit for it in the FPCCR is set. */ -bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure); +bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure); /** * armv7m_nvic_raw_execution_priority: return the raw execution priority - * @opaque: the NVIC + * @s: the NVIC * * Returns: the raw execution priority as defined by the v8M architecture. * This is the execution priority minus the effects of AIRCR.PRIS, * and minus any PRIMASK/FAULTMASK/BASEPRI priority boosting. * (v8M ARM ARM I_PKLD.) */ -int armv7m_nvic_raw_execution_priority(void *opaque); +int armv7m_nvic_raw_execution_priority(NVICState *s); /** * armv7m_nvic_neg_prio_requested: return true if the requested execution * priority is negative for the specified security state. - * @opaque: the NVIC + * @s: the NVIC * @secure: the security state to test * This corresponds to the pseudocode IsReqExecPriNeg(). */ #ifndef CONFIG_USER_ONLY -bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure); +bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure); #else -static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) +static inline bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure) { return false; } diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index b4964dca8a..25de64c43c 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -1015,7 +1015,7 @@ static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr, * that we will need later in order to do lazy FP reg stacking. */ bool is_secure = env->v7m.secure; - void *nvic = env->nvic; + NVICState *nvic = env->nvic; /* * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits * are banked and we want to update the bit in the bank for the From 165876f22cd1483931a85728584b64d860329158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 6 Feb 2023 23:35:02 +0100 Subject: [PATCH 738/814] target/arm: Declare CPU <-> NVIC helpers in 'hw/intc/armv7m_nvic.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While dozens of files include "cpu.h", only 3 files require these NVIC helper declarations. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230206223502.25122-12-philmd@linaro.org Signed-off-by: Peter Maydell --- include/hw/intc/armv7m_nvic.h | 123 ++++++++++++++++++++++++++++++++++ target/arm/cpu.c | 4 +- target/arm/cpu.h | 123 ---------------------------------- target/arm/cpu_tcg.c | 3 + target/arm/m_helper.c | 3 + 5 files changed, 132 insertions(+), 124 deletions(-) diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h index 07f9c21a5f..1ca262fbf8 100644 --- a/include/hw/intc/armv7m_nvic.h +++ b/include/hw/intc/armv7m_nvic.h @@ -83,4 +83,127 @@ struct NVICState { qemu_irq sysresetreq; }; +/* Interface between CPU and Interrupt controller. */ +/** + * armv7m_nvic_set_pending: mark the specified exception as pending + * @s: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Marks the specified exception as pending. Note that we will assert() + * if @secure is true and @irq does not specify one of the fixed set + * of architecturally banked exceptions. + */ +void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure); +/** + * armv7m_nvic_set_pending_derived: mark this derived exception as pending + * @s: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Similar to armv7m_nvic_set_pending(), but specifically for derived + * exceptions (exceptions generated in the course of trying to take + * a different exception). + */ +void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure); +/** + * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending + * @s: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Similar to armv7m_nvic_set_pending(), but specifically for exceptions + * generated in the course of lazy stacking of FP registers. + */ +void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure); +/** + * armv7m_nvic_get_pending_irq_info: return highest priority pending + * exception, and whether it targets Secure state + * @s: the NVIC + * @pirq: set to pending exception number + * @ptargets_secure: set to whether pending exception targets Secure + * + * This function writes the number of the highest priority pending + * exception (the one which would be made active by + * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure + * to true if the current highest priority pending exception should + * be taken to Secure state, false for NS. + */ +void armv7m_nvic_get_pending_irq_info(NVICState *s, int *pirq, + bool *ptargets_secure); +/** + * armv7m_nvic_acknowledge_irq: make highest priority pending exception active + * @s: the NVIC + * + * Move the current highest priority pending exception from the pending + * state to the active state, and update v7m.exception to indicate that + * it is the exception currently being handled. + */ +void armv7m_nvic_acknowledge_irq(NVICState *s); +/** + * armv7m_nvic_complete_irq: complete specified interrupt or exception + * @s: the NVIC + * @irq: the exception number to complete + * @secure: true if this exception was secure + * + * Returns: -1 if the irq was not active + * 1 if completing this irq brought us back to base (no active irqs) + * 0 if there is still an irq active after this one was completed + * (Ignoring -1, this is the same as the RETTOBASE value before completion.) + */ +int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure); +/** + * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) + * @s: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Return whether an exception is "ready", i.e. whether the exception is + * enabled and is configured at a priority which would allow it to + * interrupt the current execution priority. This controls whether the + * RDY bit for it in the FPCCR is set. + */ +bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure); +/** + * armv7m_nvic_raw_execution_priority: return the raw execution priority + * @s: the NVIC + * + * Returns: the raw execution priority as defined by the v8M architecture. + * This is the execution priority minus the effects of AIRCR.PRIS, + * and minus any PRIMASK/FAULTMASK/BASEPRI priority boosting. + * (v8M ARM ARM I_PKLD.) + */ +int armv7m_nvic_raw_execution_priority(NVICState *s); +/** + * armv7m_nvic_neg_prio_requested: return true if the requested execution + * priority is negative for the specified security state. + * @s: the NVIC + * @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 diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b3a2275b08..876ab8f3bf 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -36,8 +36,10 @@ #if !defined(CONFIG_USER_ONLY) #include "hw/loader.h" #include "hw/boards.h" +#ifdef CONFIG_TCG #include "hw/intc/armv7m_nvic.h" -#endif +#endif /* CONFIG_TCG */ +#endif /* !CONFIG_USER_ONLY */ #include "sysemu/tcg.h" #include "sysemu/qtest.h" #include "sysemu/hw_accel.h" diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9a80819d8d..d623afe84a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2559,129 +2559,6 @@ void arm_cpu_list(void); uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); -/* Interface between CPU and Interrupt controller. */ -#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 -/** - * armv7m_nvic_set_pending: mark the specified exception as pending - * @s: the NVIC - * @irq: the exception number to mark pending - * @secure: false for non-banked exceptions or for the nonsecure - * version of a banked exception, true for the secure version of a banked - * exception. - * - * Marks the specified exception as pending. Note that we will assert() - * if @secure is true and @irq does not specify one of the fixed set - * of architecturally banked exceptions. - */ -void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure); -/** - * armv7m_nvic_set_pending_derived: mark this derived exception as pending - * @s: the NVIC - * @irq: the exception number to mark pending - * @secure: false for non-banked exceptions or for the nonsecure - * version of a banked exception, true for the secure version of a banked - * exception. - * - * Similar to armv7m_nvic_set_pending(), but specifically for derived - * exceptions (exceptions generated in the course of trying to take - * a different exception). - */ -void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure); -/** - * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending - * @s: the NVIC - * @irq: the exception number to mark pending - * @secure: false for non-banked exceptions or for the nonsecure - * version of a banked exception, true for the secure version of a banked - * exception. - * - * Similar to armv7m_nvic_set_pending(), but specifically for exceptions - * generated in the course of lazy stacking of FP registers. - */ -void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure); -/** - * armv7m_nvic_get_pending_irq_info: return highest priority pending - * exception, and whether it targets Secure state - * @s: the NVIC - * @pirq: set to pending exception number - * @ptargets_secure: set to whether pending exception targets Secure - * - * This function writes the number of the highest priority pending - * exception (the one which would be made active by - * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure - * to true if the current highest priority pending exception should - * be taken to Secure state, false for NS. - */ -void armv7m_nvic_get_pending_irq_info(NVICState *s, int *pirq, - bool *ptargets_secure); -/** - * armv7m_nvic_acknowledge_irq: make highest priority pending exception active - * @s: the NVIC - * - * Move the current highest priority pending exception from the pending - * state to the active state, and update v7m.exception to indicate that - * it is the exception currently being handled. - */ -void armv7m_nvic_acknowledge_irq(NVICState *s); -/** - * armv7m_nvic_complete_irq: complete specified interrupt or exception - * @s: the NVIC - * @irq: the exception number to complete - * @secure: true if this exception was secure - * - * Returns: -1 if the irq was not active - * 1 if completing this irq brought us back to base (no active irqs) - * 0 if there is still an irq active after this one was completed - * (Ignoring -1, this is the same as the RETTOBASE value before completion.) - */ -int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure); -/** - * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure) - * @s: the NVIC - * @irq: the exception number to mark pending - * @secure: false for non-banked exceptions or for the nonsecure - * version of a banked exception, true for the secure version of a banked - * exception. - * - * Return whether an exception is "ready", i.e. whether the exception is - * enabled and is configured at a priority which would allow it to - * interrupt the current execution priority. This controls whether the - * RDY bit for it in the FPCCR is set. - */ -bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure); -/** - * armv7m_nvic_raw_execution_priority: return the raw execution priority - * @s: the NVIC - * - * Returns: the raw execution priority as defined by the v8M architecture. - * This is the execution priority minus the effects of AIRCR.PRIS, - * and minus any PRIMASK/FAULTMASK/BASEPRI priority boosting. - * (v8M ARM ARM I_PKLD.) - */ -int armv7m_nvic_raw_execution_priority(NVICState *s); -/** - * armv7m_nvic_neg_prio_requested: return true if the requested execution - * priority is negative for the specified security state. - * @s: the NVIC - * @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 - /* Interface for defining coprocessor registers. * Registers are defined in tables of arm_cp_reginfo structs * which are passed to define_arm_cp_regs(). diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index ccde5080eb..df0c45e523 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -19,6 +19,9 @@ #include "hw/boards.h" #endif #include "cpregs.h" +#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) +#include "hw/intc/armv7m_nvic.h" +#endif /* Share AArch32 -cpu max features with AArch64. */ diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 25de64c43c..f94e87e728 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -18,6 +18,9 @@ #include "exec/cpu_ldst.h" #include "semihosting/common-semi.h" #endif +#if !defined(CONFIG_USER_ONLY) +#include "hw/intc/armv7m_nvic.h" +#endif static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask, uint32_t reg, uint32_t val) From dbba45e6aa1048626faabff5f6bc2b341f87166f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 3 Feb 2023 18:16:32 +0000 Subject: [PATCH 739/814] tests/avocado: retire the Aarch64 TCG tests from boot_linux.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two TCG tests for GICv2 and GICv3 are very heavy weight distros that take a long time to boot up, especially for an --enable-debug build. The total code coverage they give is: Overall coverage rate: lines......: 11.2% (59584 of 530123 lines) functions..: 15.0% (7436 of 49443 functions) branches...: 6.3% (19273 of 303933 branches) We already get pretty close to that with the machine_aarch64_virt tests which only does one full boot (~120s vs ~600s) of alpine. We expand the kernel+initrd boot (~8s) to test both GICs and also add an RNG device and a block device to generate a few IRQs and exercise the storage layer. With that we get to a coverage of: Overall coverage rate: lines......: 11.0% (58121 of 530123 lines) functions..: 14.9% (7343 of 49443 functions) branches...: 6.0% (18269 of 303933 branches) which I feel is close enough given the massive time saving. If we want to target any more sub-systems we can use lighter weight more directed tests. Signed-off-by: Alex Bennée Reviewed-by: Fabiano Rosas Acked-by: Richard Henderson Message-id: 20230203181632.2919715-1-alex.bennee@linaro.org Cc: Peter Maydell Signed-off-by: Peter Maydell --- tests/avocado/boot_linux.py | 48 ++++---------------- tests/avocado/machine_aarch64_virt.py | 63 ++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py index b3e58fa309..fe0bb180d9 100644 --- a/tests/avocado/boot_linux.py +++ b/tests/avocado/boot_linux.py @@ -58,52 +58,16 @@ class BootLinuxX8664(LinuxTest): self.launch_and_wait(set_up_ssh_connection=False) -# For Aarch64 we only boot KVM tests in CI as the TCG tests are very -# heavyweight. There are lighter weight distros which we use in the -# machine_aarch64_virt.py tests. +# 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 - :avocado: tags=machine:gic-version=2 """ timeout = 720 - def add_common_args(self): - 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') - - @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') - def test_fedora_cloud_tcg_gicv2(self): - """ - :avocado: tags=accel:tcg - :avocado: tags=cpu:max - :avocado: tags=device:gicv2 - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.vm.add_args("-cpu", "max,lpa2=off") - self.vm.add_args("-machine", "virt,gic-version=2") - self.add_common_args() - self.launch_and_wait(set_up_ssh_connection=False) - - @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab') - def test_fedora_cloud_tcg_gicv3(self): - """ - :avocado: tags=accel:tcg - :avocado: tags=cpu:max - :avocado: tags=device:gicv3 - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.vm.add_args("-cpu", "max,lpa2=off") - self.vm.add_args("-machine", "virt,gic-version=3") - self.add_common_args() - self.launch_and_wait(set_up_ssh_connection=False) - def test_virt_kvm(self): """ :avocado: tags=accel:kvm @@ -112,7 +76,11 @@ class BootLinuxAarch64(LinuxTest): self.require_accelerator("kvm") self.vm.add_args("-accel", "kvm") self.vm.add_args("-machine", "virt,gic-version=host") - self.add_common_args() + 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) diff --git a/tests/avocado/machine_aarch64_virt.py b/tests/avocado/machine_aarch64_virt.py index c2b2ba2cf8..25dab8dc00 100644 --- a/tests/avocado/machine_aarch64_virt.py +++ b/tests/avocado/machine_aarch64_virt.py @@ -10,11 +10,14 @@ import time import os +import logging from avocado_qemu import QemuSystemTest from avocado_qemu import wait_for_console_pattern from avocado_qemu import exec_command from avocado_qemu import BUILD_DIR +from avocado.utils import process +from avocado.utils.path import find_command class Aarch64VirtMachine(QemuSystemTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' @@ -65,16 +68,15 @@ class Aarch64VirtMachine(QemuSystemTest): self.wait_for_console_pattern('Welcome to Alpine Linux 3.16') - def test_aarch64_virt(self): + def common_aarch64_virt(self, machine): """ - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - :avocado: tags=accel:tcg - :avocado: tags=cpu:max + Common code to launch basic virt machine with kernel+initrd + and a scratch disk. """ + logger = logging.getLogger('aarch64_virt') + kernel_url = ('https://fileserver.linaro.org/s/' 'z6B2ARM7DQT3HWN/download') - kernel_hash = 'ed11daab50c151dde0e1e9c9cb8b2d9bd3215347' kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) @@ -83,13 +85,62 @@ class Aarch64VirtMachine(QemuSystemTest): 'console=ttyAMA0') self.require_accelerator("tcg") self.vm.add_args('-cpu', 'max,pauth-impdef=on', + '-machine', machine, '-accel', 'tcg', '-kernel', kernel_path, '-append', kernel_command_line) + + # A RNG offers an easy way to generate a few IRQs + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', + 'rng-random,id=rng0,filename=/dev/urandom') + + # Also add a scratch block device + logger.info('creating scratch qcow2 image') + image_path = os.path.join(self.workdir, 'scratch.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') + cmd = '%s create -f qcow2 %s 8M' % (qemu_img, image_path) + process.run(cmd) + + # Add the device + self.vm.add_args('-blockdev', + f"driver=qcow2,file.driver=file,file.filename={image_path},node-name=scratch") + self.vm.add_args('-device', + 'virtio-blk-device,drive=scratch') + self.vm.launch() self.wait_for_console_pattern('Welcome to Buildroot') time.sleep(0.1) exec_command(self, 'root') time.sleep(0.1) + exec_command(self, 'dd if=/dev/hwrng of=/dev/vda bs=512 count=4') + time.sleep(0.1) + exec_command(self, 'md5sum /dev/vda') + time.sleep(0.1) + exec_command(self, 'cat /proc/interrupts') + time.sleep(0.1) exec_command(self, 'cat /proc/self/maps') time.sleep(0.1) + + def test_aarch64_virt_gicv3(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=accel:tcg + :avocado: tags=cpu:max + """ + self.common_aarch64_virt("virt,gic_version=3") + + def test_aarch64_virt_gicv2(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=accel:tcg + :avocado: tags=cpu:max + """ + self.common_aarch64_virt("virt,gic-version=2") From c2ecb424fb15ba0db0d9445721e6e8a8e79c4976 Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Tue, 14 Feb 2023 09:40:09 +0000 Subject: [PATCH 740/814] hw/arm/smmuv3: Add GBPA register GBPA register can be used to globally abort all transactions. It is described in the SMMU manual in "6.3.14 SMMU_GBPA". ABORT reset value is IMPLEMENTATION DEFINED, it is chosen to be zero(Do not abort incoming transactions). Other fields have default values of Use Incoming. If UPDATE is not set, the write is ignored. This is the only permitted behavior in SMMUv3.2 and later.(6.3.14.1 Update procedure) As this patch adds a new state to the SMMU (GBPA), it is added in a new subsection for forward migration compatibility. GBPA is only migrated if its value is different from the reset value. It does this to be backward migration compatible if SW didn't write the register. Signed-off-by: Mostafa Saleh Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Message-id: 20230214094009.2445653-1-smostafa@google.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/smmuv3-internal.h | 7 +++++++ hw/arm/smmuv3.c | 43 +++++++++++++++++++++++++++++++++++++++- include/hw/arm/smmuv3.h | 1 + 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index bce161870f..e8f0ebf25e 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -79,6 +79,13 @@ REG32(CR0ACK, 0x24) REG32(CR1, 0x28) REG32(CR2, 0x2c) REG32(STATUSR, 0x40) +REG32(GBPA, 0x44) + FIELD(GBPA, ABORT, 20, 1) + FIELD(GBPA, UPDATE, 31, 1) + +/* Use incoming. */ +#define SMMU_GBPA_RESET_VAL 0x1000 + REG32(IRQ_CTRL, 0x50) FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1) FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 955b89c8d5..270c80b665 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -285,6 +285,7 @@ static void smmuv3_init_regs(SMMUv3State *s) s->gerror = 0; s->gerrorn = 0; s->statusr = 0; + s->gbpa = SMMU_GBPA_RESET_VAL; } static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf, @@ -659,7 +660,11 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, qemu_mutex_lock(&s->mutex); if (!smmu_enabled(s)) { - status = SMMU_TRANS_DISABLE; + if (FIELD_EX32(s->gbpa, GBPA, ABORT)) { + status = SMMU_TRANS_ABORT; + } else { + status = SMMU_TRANS_DISABLE; + } goto epilogue; } @@ -1170,6 +1175,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset, case A_GERROR_IRQ_CFG2: s->gerror_irq_cfg2 = data; return MEMTX_OK; + case A_GBPA: + /* + * If UPDATE is not set, the write is ignored. This is the only + * permitted behavior in SMMUv3.2 and later. + */ + if (data & R_GBPA_UPDATE_MASK) { + /* Ignore update bit as write is synchronous. */ + s->gbpa = data & ~R_GBPA_UPDATE_MASK; + } + return MEMTX_OK; case A_STRTAB_BASE: /* 64b */ s->strtab_base = deposit64(s->strtab_base, 0, 32, data); return MEMTX_OK; @@ -1318,6 +1333,9 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset, case A_STATUSR: *data = s->statusr; return MEMTX_OK; + case A_GBPA: + *data = s->gbpa; + return MEMTX_OK; case A_IRQ_CTRL: case A_IRQ_CTRL_ACK: *data = s->irq_ctrl; @@ -1482,6 +1500,25 @@ static const VMStateDescription vmstate_smmuv3_queue = { }, }; +static bool smmuv3_gbpa_needed(void *opaque) +{ + SMMUv3State *s = opaque; + + /* Only migrate GBPA if it has different reset value. */ + return s->gbpa != SMMU_GBPA_RESET_VAL; +} + +static const VMStateDescription vmstate_gbpa = { + .name = "smmuv3/gbpa", + .version_id = 1, + .minimum_version_id = 1, + .needed = smmuv3_gbpa_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(gbpa, SMMUv3State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_smmuv3 = { .name = "smmuv3", .version_id = 1, @@ -1512,6 +1549,10 @@ static const VMStateDescription vmstate_smmuv3 = { VMSTATE_END_OF_LIST(), }, + .subsections = (const VMStateDescription * []) { + &vmstate_gbpa, + NULL + } }; static void smmuv3_instance_init(Object *obj) diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index b6dd087526..a0c026402e 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -45,6 +45,7 @@ struct SMMUv3State { uint32_t cr[3]; uint32_t cr0ack; uint32_t statusr; + uint32_t gbpa; uint32_t irq_ctrl; uint32_t gerror; uint32_t gerrorn; From f4880c2da4c8eadfee3f40b76af77f77574cebef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 16 Feb 2023 10:23:27 +0100 Subject: [PATCH 741/814] hw/arm: Add missing XLNX_ZYNQMP_ARM -> USB_DWC3 Kconfig dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit acc0b8b05a when running the ZynqMP ZCU102 board with a QEMU configured using --without-default-devices, we get: $ qemu-system-aarch64 -M xlnx-zcu102 qemu-system-aarch64: missing object type 'usb_dwc3' Abort trap: 6 Fix by adding the missing Kconfig dependency. Fixes: acc0b8b05a ("hw/arm/xlnx-zynqmp: Connect ZynqMP's USB controllers") Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230216092327.2203-1-philmd@linaro.org Reviewed-by: Francisco Iglesias Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 2d157de9b8..b5aed4aff5 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -389,6 +389,7 @@ config XLNX_ZYNQMP_ARM select XLNX_CSU_DMA select XLNX_ZYNQMP select XLNX_ZDMA + select USB_DWC3 config XLNX_VERSAL bool From 8e4f2b277b4c1e1460a22e16e59fa11e6c36fcf4 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 3 Feb 2023 14:44:31 +0100 Subject: [PATCH 742/814] arm/virt: don't try to spell out the accelerator Just use current_accel_name() directly. Signed-off-by: Cornelia Huck Reviewed-by: Eric Auger Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/virt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 75f28947de..8d13e4486b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2133,21 +2133,21 @@ static void machvirt_init(MachineState *machine) if (vms->secure && (kvm_enabled() || hvf_enabled())) { error_report("mach-virt: %s does not support providing " "Security extensions (TrustZone) to the guest CPU", - kvm_enabled() ? "KVM" : "HVF"); + current_accel_name()); exit(1); } if (vms->virt && (kvm_enabled() || hvf_enabled())) { error_report("mach-virt: %s does not support providing " "Virtualization extensions to the guest CPU", - kvm_enabled() ? "KVM" : "HVF"); + current_accel_name()); exit(1); } if (vms->mte && (kvm_enabled() || hvf_enabled())) { error_report("mach-virt: %s does not support providing " "MTE to the guest CPU", - kvm_enabled() ? "KVM" : "HVF"); + current_accel_name()); exit(1); } From 73c793dab2d3dd07a0b6c9312d645863ca46c128 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Wed, 8 Feb 2023 15:54:31 -0800 Subject: [PATCH 743/814] MAINTAINERS: Add myself to maintainers and remove Havard Havard is no longer working on the Nuvoton systems for a while and won't be able to do any work on it in the future. So I'll take over maintaining the Nuvoton system from him. Signed-off-by: Hao Wu Acked-by: Havard Skinnemoen Reviewed-by: Philippe Mathieu-Daude Message-id: 20230208235433.3989937-2-wuhaotsh@google.com Signed-off-by: Peter Maydell --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fd54c1f140..94659e42c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -807,8 +807,8 @@ F: include/hw/net/mv88w8618_eth.h F: docs/system/arm/musicpal.rst Nuvoton NPCM7xx -M: Havard Skinnemoen M: Tyrone Ting +M: Hao Wu L: qemu-arm@nongnu.org S: Supported F: hw/*/npcm7xx* From 69fbfb8ff1369bd51ada1b4fb9b800e3e8d92fba Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Wed, 8 Feb 2023 15:54:32 -0800 Subject: [PATCH 744/814] hw/ssi: Add Nuvoton PSPI Module Nuvoton's PSPI is a general purpose SPI module which enables connections to SPI-based peripheral devices. Signed-off-by: Hao Wu Reviewed-by: Chris Rauer Reviewed-by: Philippe Mathieu-Daude Message-id: 20230208235433.3989937-3-wuhaotsh@google.com Signed-off-by: Peter Maydell --- MAINTAINERS | 6 +- hw/ssi/meson.build | 2 +- hw/ssi/npcm_pspi.c | 221 +++++++++++++++++++++++++++++++++++++ hw/ssi/trace-events | 5 + include/hw/ssi/npcm_pspi.h | 53 +++++++++ 5 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 hw/ssi/npcm_pspi.c create mode 100644 include/hw/ssi/npcm_pspi.h diff --git a/MAINTAINERS b/MAINTAINERS index 94659e42c2..21595f0aad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -811,9 +811,9 @@ M: Tyrone Ting M: Hao Wu L: qemu-arm@nongnu.org S: Supported -F: hw/*/npcm7xx* -F: include/hw/*/npcm7xx* -F: tests/qtest/npcm7xx* +F: hw/*/npcm* +F: include/hw/*/npcm* +F: tests/qtest/npcm* F: pc-bios/npcm7xx_bootrom.bin F: roms/vbootrom F: docs/system/arm/nuvoton.rst diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 702aa5e4df..904a47161a 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -1,6 +1,6 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c')) -softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c')) +softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 'npcm_pspi.c')) softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c')) softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c')) diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c new file mode 100644 index 0000000000..3fb935043a --- /dev/null +++ b/hw/ssi/npcm_pspi.c @@ -0,0 +1,221 @@ +/* + * Nuvoton NPCM Peripheral SPI Module (PSPI) + * + * Copyright 2023 Google LLC + * + * 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. + */ + +#include "qemu/osdep.h" + +#include "hw/irq.h" +#include "hw/registerfields.h" +#include "hw/ssi/npcm_pspi.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" + +#include "trace.h" + +REG16(PSPI_DATA, 0x0) +REG16(PSPI_CTL1, 0x2) + FIELD(PSPI_CTL1, SPIEN, 0, 1) + FIELD(PSPI_CTL1, MOD, 2, 1) + FIELD(PSPI_CTL1, EIR, 5, 1) + FIELD(PSPI_CTL1, EIW, 6, 1) + FIELD(PSPI_CTL1, SCM, 7, 1) + FIELD(PSPI_CTL1, SCIDL, 8, 1) + FIELD(PSPI_CTL1, SCDV, 9, 7) +REG16(PSPI_STAT, 0x4) + FIELD(PSPI_STAT, BSY, 0, 1) + FIELD(PSPI_STAT, RBF, 1, 1) + +static void npcm_pspi_update_irq(NPCMPSPIState *s) +{ + int level = 0; + + /* Only fire IRQ when the module is enabled. */ + if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, SPIEN)) { + /* Update interrupt as BSY is cleared. */ + if ((!FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, BSY)) && + FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIW)) { + level = 1; + } + + /* Update interrupt as RBF is set. */ + if (FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, RBF) && + FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIR)) { + level = 1; + } + } + qemu_set_irq(s->irq, level); +} + +static uint16_t npcm_pspi_read_data(NPCMPSPIState *s) +{ + uint16_t value = s->regs[R_PSPI_DATA]; + + /* Clear stat bits as the value are read out. */ + s->regs[R_PSPI_STAT] = 0; + + return value; +} + +static void npcm_pspi_write_data(NPCMPSPIState *s, uint16_t data) +{ + uint16_t value = 0; + + if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, MOD)) { + value = ssi_transfer(s->spi, extract16(data, 8, 8)) << 8; + } + value |= ssi_transfer(s->spi, extract16(data, 0, 8)); + s->regs[R_PSPI_DATA] = value; + + /* Mark data as available */ + s->regs[R_PSPI_STAT] = R_PSPI_STAT_BSY_MASK | R_PSPI_STAT_RBF_MASK; +} + +/* Control register read handler. */ +static uint64_t npcm_pspi_ctrl_read(void *opaque, hwaddr addr, + unsigned int size) +{ + NPCMPSPIState *s = opaque; + uint16_t value; + + switch (addr) { + case A_PSPI_DATA: + value = npcm_pspi_read_data(s); + break; + + case A_PSPI_CTL1: + value = s->regs[R_PSPI_CTL1]; + break; + + case A_PSPI_STAT: + value = s->regs[R_PSPI_STAT]; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to invalid offset 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + return 0; + } + trace_npcm_pspi_ctrl_read(DEVICE(s)->canonical_path, addr, value); + npcm_pspi_update_irq(s); + + return value; +} + +/* Control register write handler. */ +static void npcm_pspi_ctrl_write(void *opaque, hwaddr addr, uint64_t v, + unsigned int size) +{ + NPCMPSPIState *s = opaque; + uint16_t value = v; + + trace_npcm_pspi_ctrl_write(DEVICE(s)->canonical_path, addr, value); + + switch (addr) { + case A_PSPI_DATA: + npcm_pspi_write_data(s, value); + break; + + case A_PSPI_CTL1: + s->regs[R_PSPI_CTL1] = value; + break; + + case A_PSPI_STAT: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to read-only register PSPI_STAT: 0x%08" + PRIx64 "\n", DEVICE(s)->canonical_path, v); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: write to invalid offset 0x%" PRIx64 "\n", + DEVICE(s)->canonical_path, addr); + return; + } + npcm_pspi_update_irq(s); +} + +static const MemoryRegionOps npcm_pspi_ctrl_ops = { + .read = npcm_pspi_ctrl_read, + .write = npcm_pspi_ctrl_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 2, + .unaligned = false, + }, + .impl = { + .min_access_size = 2, + .max_access_size = 2, + .unaligned = false, + }, +}; + +static void npcm_pspi_enter_reset(Object *obj, ResetType type) +{ + NPCMPSPIState *s = NPCM_PSPI(obj); + + trace_npcm_pspi_enter_reset(DEVICE(obj)->canonical_path, type); + memset(s->regs, 0, sizeof(s->regs)); +} + +static void npcm_pspi_realize(DeviceState *dev, Error **errp) +{ + NPCMPSPIState *s = NPCM_PSPI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + Object *obj = OBJECT(dev); + + s->spi = ssi_create_bus(dev, "pspi"); + memory_region_init_io(&s->mmio, obj, &npcm_pspi_ctrl_ops, s, + "mmio", 4 * KiB); + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_irq(sbd, &s->irq); +} + +static const VMStateDescription vmstate_npcm_pspi = { + .name = "npcm-pspi", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16_ARRAY(regs, NPCMPSPIState, NPCM_PSPI_NR_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + + +static void npcm_pspi_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "NPCM Peripheral SPI Module"; + dc->realize = npcm_pspi_realize; + dc->vmsd = &vmstate_npcm_pspi; + rc->phases.enter = npcm_pspi_enter_reset; +} + +static const TypeInfo npcm_pspi_types[] = { + { + .name = TYPE_NPCM_PSPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NPCMPSPIState), + .class_init = npcm_pspi_class_init, + }, +}; +DEFINE_TYPES(npcm_pspi_types); diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index c707d4aaba..2d5bd2b83d 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -21,6 +21,11 @@ npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset: npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 npcm7xx_fiu_flash_write(const char *id, unsigned cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64 +# npcm_pspi.c +npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type: %d" +npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16 +npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16 + # ibex_spi_host.c ibex_spi_host_reset(const char *msg) "%s" diff --git a/include/hw/ssi/npcm_pspi.h b/include/hw/ssi/npcm_pspi.h new file mode 100644 index 0000000000..37cc784d96 --- /dev/null +++ b/include/hw/ssi/npcm_pspi.h @@ -0,0 +1,53 @@ +/* + * Nuvoton Peripheral SPI Module + * + * Copyright 2023 Google LLC + * + * 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. + */ +#ifndef NPCM_PSPI_H +#define NPCM_PSPI_H + +#include "hw/ssi/ssi.h" +#include "hw/sysbus.h" + +/* + * Number of registers in our device state structure. Don't change this without + * incrementing the version_id in the vmstate. + */ +#define NPCM_PSPI_NR_REGS 3 + +/** + * NPCMPSPIState - Device state for one Flash Interface Unit. + * @parent: System bus device. + * @mmio: Memory region for register access. + * @spi: The SPI bus mastered by this controller. + * @regs: Register contents. + * @irq: The interrupt request queue for this module. + * + * Each PSPI has a shared bank of registers, and controls up to four chip + * selects. Each chip select has a dedicated memory region which may be used to + * read and write the flash connected to that chip select as if it were memory. + */ +typedef struct NPCMPSPIState { + SysBusDevice parent; + + MemoryRegion mmio; + + SSIBus *spi; + uint16_t regs[NPCM_PSPI_NR_REGS]; + qemu_irq irq; +} NPCMPSPIState; + +#define TYPE_NPCM_PSPI "npcm-pspi" +OBJECT_DECLARE_SIMPLE_TYPE(NPCMPSPIState, NPCM_PSPI) + +#endif /* NPCM_PSPI_H */ From 4d120d7d6084ef388a9016d7dbf091c4d5e055fc Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Wed, 8 Feb 2023 15:54:33 -0800 Subject: [PATCH 745/814] hw/arm: Attach PSPI module to NPCM7XX SoC Signed-off-by: Hao Wu Reviewed-by: Titus Rwantare Reviewed-by: Philippe Mathieu-Daude Message-id: 20230208235433.3989937-4-wuhaotsh@google.com Signed-off-by: Peter Maydell --- docs/system/arm/nuvoton.rst | 2 +- hw/arm/npcm7xx.c | 25 +++++++++++++++++++++++-- include/hw/arm/npcm7xx.h | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst index c38df32bde..0424cae4b0 100644 --- a/docs/system/arm/nuvoton.rst +++ b/docs/system/arm/nuvoton.rst @@ -49,6 +49,7 @@ Supported devices * SMBus controller (SMBF) * Ethernet controller (EMC) * Tachometer + * Peripheral SPI controller (PSPI) Missing devices --------------- @@ -64,7 +65,6 @@ Missing devices * Ethernet controller (GMAC) * USB device (USBD) - * Peripheral SPI controller (PSPI) * SD/MMC host * PECI interface * PCI and PCIe root complex and bridges diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index d85cc02765..15ff21d047 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -86,6 +86,8 @@ enum NPCM7xxInterrupt { NPCM7XX_EMC1RX_IRQ = 15, NPCM7XX_EMC1TX_IRQ, NPCM7XX_MMC_IRQ = 26, + NPCM7XX_PSPI2_IRQ = 28, + NPCM7XX_PSPI1_IRQ = 31, NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */ NPCM7XX_TIMER1_IRQ, NPCM7XX_TIMER2_IRQ, @@ -220,6 +222,12 @@ static const hwaddr npcm7xx_emc_addr[] = { 0xf0826000, }; +/* Register base address for each PSPI Module */ +static const hwaddr npcm7xx_pspi_addr[] = { + 0xf0200000, + 0xf0201000, +}; + static const struct { hwaddr regs_addr; uint32_t unconnected_pins; @@ -444,6 +452,10 @@ static void npcm7xx_init(Object *obj) object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC); } + for (i = 0; i < ARRAY_SIZE(s->pspi); i++) { + object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI); + } + object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); } @@ -715,6 +727,17 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0, npcm7xx_irq(s, NPCM7XX_MMC_IRQ)); + /* PSPI */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pspi_addr) != ARRAY_SIZE(s->pspi)); + for (i = 0; i < ARRAY_SIZE(s->pspi); i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pspi[i]); + int irq = (i == 0) ? NPCM7XX_PSPI1_IRQ : NPCM7XX_PSPI2_IRQ; + + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, npcm7xx_pspi_addr[i]); + sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq)); + } + create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB); create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB); create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB); @@ -724,8 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB); create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB); create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); - create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB); - create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB); create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB); diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index f1b7e4a48d..72c7722096 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -32,6 +32,7 @@ #include "hw/nvram/npcm7xx_otp.h" #include "hw/timer/npcm7xx_timer.h" #include "hw/ssi/npcm7xx_fiu.h" +#include "hw/ssi/npcm_pspi.h" #include "hw/usb/hcd-ehci.h" #include "hw/usb/hcd-ohci.h" #include "target/arm/cpu.h" @@ -104,6 +105,7 @@ struct NPCM7xxState { NPCM7xxFIUState fiu[2]; NPCM7xxEMCState emc[2]; NPCM7xxSDHCIState mmc; + NPCMPSPIState pspi[2]; }; #define TYPE_NPCM7XX "npcm7xx" From ca3fbed896ec867ea0826b9859c6636ca927e835 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Tue, 14 Feb 2023 17:19:21 +0000 Subject: [PATCH 746/814] hw/arm/smmu-common: Support 64-bit addresses Addresses targeting the second translation table (TTB1) in the SMMU have all upper bits set. Ensure the IOMMU region covers all 64 bits. Reviewed-by: Richard Henderson Signed-off-by: Jean-Philippe Brucker Reviewed-by: Eric Auger Message-id: 20230214171921.1917916-2-jean-philippe@linaro.org Signed-off-by: Peter Maydell --- hw/arm/smmu-common.c | 2 +- include/hw/arm/smmu-common.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 733c964778..2b8c67b9a1 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -439,7 +439,7 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu), s->mrtypename, - OBJECT(s), name, 1ULL << SMMU_MAX_VA_BITS); + OBJECT(s), name, UINT64_MAX); address_space_init(&sdev->as, MEMORY_REGION(&sdev->iommu), name); trace_smmu_add_mr(name); diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index c5683af07d..9fcff26357 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -27,8 +27,6 @@ #define SMMU_PCI_DEVFN_MAX 256 #define SMMU_PCI_DEVFN(sid) (sid & 0xFF) -#define SMMU_MAX_VA_BITS 48 - /* * Page table walk error types */ From e431b8f608d22b0bca64b75b8738b2a6ab4468bd Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Tue, 14 Feb 2023 17:19:22 +0000 Subject: [PATCH 747/814] hw/arm/smmu-common: Fix TTB1 handling Addresses targeting the second translation table (TTB1) in the SMMU have all upper bits set (except for the top byte when TBI is enabled). Fix the TTB1 check. Reported-by: Ola Hugosson Reviewed-by: Eric Auger Reviewed-by: Richard Henderson Signed-off-by: Jean-Philippe Brucker Message-id: 20230214171921.1917916-3-jean-philippe@linaro.org Signed-off-by: Peter Maydell --- hw/arm/smmu-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 2b8c67b9a1..0a5a60ca1e 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -249,7 +249,7 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova) /* there is a ttbr0 region and we are in it (high bits all zero) */ return &cfg->tt[0]; } else if (cfg->tt[1].tsz && - !extract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte)) { + sextract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte) == -1) { /* there is a ttbr1 region and we are in it (high bits all one) */ return &cfg->tt[1]; } else if (!cfg->tt[0].tsz) { From a06e3a68ba2b0f51d28f83e94f8266811c0ba05c Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 13 Feb 2023 17:29:00 -0300 Subject: [PATCH 748/814] target/arm: rename handle_semihosting to tcg_handle_semihosting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make it clearer from the name that this is a tcg-only function. Signed-off-by: Claudio Fontana Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 22670c20c0..509e674b0f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11014,7 +11014,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) * trapped to the hypervisor in KVM. */ #ifdef CONFIG_TCG -static void handle_semihosting(CPUState *cs) +static void tcg_handle_semihosting(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -11076,7 +11076,7 @@ void arm_cpu_do_interrupt(CPUState *cs) */ #ifdef CONFIG_TCG if (cs->exception_index == EXCP_SEMIHOST) { - handle_semihosting(cs); + tcg_handle_semihosting(cs); return; } #endif From 0c1aaa66c248b7375112a2d6f5ca3bafaeda0aa5 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 13 Feb 2023 17:29:01 -0300 Subject: [PATCH 749/814] target/arm: wrap psci call with tcg_enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for "all" builds (tcg + kvm), we want to avoid doing the psci check if tcg is built-in, but not enabled. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Signed-off-by: Fabiano Rosas Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 509e674b0f..2d38c3ed7a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -22,6 +22,7 @@ #include "hw/irq.h" #include "sysemu/cpu-timers.h" #include "sysemu/kvm.h" +#include "sysemu/tcg.h" #include "qapi/qapi-commands-machine-target.h" #include "qapi/error.h" #include "qemu/guest-random.h" @@ -11063,7 +11064,7 @@ void arm_cpu_do_interrupt(CPUState *cs) env->exception.syndrome); } - if (arm_is_psci_call(cpu, cs->exception_index)) { + if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) { arm_handle_psci_call(cpu); qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n"); return; From d55b2a2aa37ab07eed1517791344392b3c147f09 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 13 Feb 2023 17:29:02 -0300 Subject: [PATCH 750/814] target/arm: wrap call to aarch64_sve_change_el in tcg_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Signed-off-by: Fabiano Rosas Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/helper.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2d38c3ed7a..07d4100365 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10827,11 +10827,13 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) unsigned int cur_el = arm_current_el(env); int rt; - /* - * Note that new_el can never be 0. If cur_el is 0, then - * el0_a64 is is_a64(), else el0_a64 is ignored. - */ - aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); + if (tcg_enabled()) { + /* + * Note that new_el can never be 0. If cur_el is 0, then + * el0_a64 is is_a64(), else el0_a64 is ignored. + */ + aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); + } if (cur_el < new_el) { /* From 501e6d1f6c75e9bc844098fd13fca730188056ef Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:03 -0300 Subject: [PATCH 751/814] target/arm: Move PC alignment check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move this earlier to make the next patch diff cleaner. While here update the comment slightly to not give the impression that the misalignment affects only TCG. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Fabiano Rosas Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/machine.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index 5f26152652..b4c3850570 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -839,6 +839,15 @@ static int cpu_post_load(void *opaque, int version_id) } } + /* + * Misaligned thumb pc is architecturally impossible. Fail the + * incoming migration. For TCG it would trigger the assert in + * thumb_tr_translate_insn(). + */ + if (!is_a64(env) && env->thumb && (env->regs[15] & 1)) { + return -1; + } + hw_breakpoint_update_all(cpu); hw_watchpoint_update_all(cpu); @@ -856,15 +865,6 @@ static int cpu_post_load(void *opaque, int version_id) } } - /* - * Misaligned thumb pc is architecturally impossible. - * We have an assert in thumb_tr_translate_insn to verify this. - * Fail an incoming migrate to avoid this assert. - */ - if (!is_a64(env) && env->thumb && (env->regs[15] & 1)) { - return -1; - } - if (!kvm_enabled()) { pmu_op_finish(&cpu->env); } From 9200d5cc749fe06c52da395d94f39aaa5c380635 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:04 -0300 Subject: [PATCH 752/814] target/arm: Move cpregs code out of cpu.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit cf7c6d1004 ("target/arm: Split out cpregs.h") we now have a cpregs.h header which is more suitable for this code. Code moved verbatim. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 98 +++++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 91 ----------------------------------------- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index efcf9181b9..1ee64e99de 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -120,6 +120,104 @@ enum { ARM_CP_SME = 1 << 19, }; +/* + * Interface for defining coprocessor registers. + * Registers are defined in tables of arm_cp_reginfo structs + * which are passed to define_arm_cp_regs(). + */ + +/* + * When looking up a coprocessor register we look for it + * via an integer which encodes all of: + * coprocessor number + * Crn, Crm, opc1, opc2 fields + * 32 or 64 bit register (ie is it accessed via MRC/MCR + * or via MRRC/MCRR?) + * non-secure/secure bank (AArch32 only) + * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field. + * (In this case crn and opc2 should be zero.) + * For AArch64, there is no 32/64 bit size distinction; + * instead all registers have a 2 bit op0, 3 bit op1 and op2, + * and 4 bit CRn and CRm. The encoding patterns are chosen + * to be easy to convert to and from the KVM encodings, and also + * so that the hashtable can contain both AArch32 and AArch64 + * registers (to allow for interprocessing where we might run + * 32 bit code on a 64 bit core). + */ +/* + * This bit is private to our hashtable cpreg; in KVM register + * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64 + * in the upper bits of the 64 bit ID. + */ +#define CP_REG_AA64_SHIFT 28 +#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT) + +/* + * To enable banking of coprocessor registers depending on ns-bit we + * add a bit to distinguish between secure and non-secure cpregs in the + * hashtable. + */ +#define CP_REG_NS_SHIFT 29 +#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT) + +#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \ + ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \ + ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2)) + +#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \ + (CP_REG_AA64_MASK | \ + ((cp) << CP_REG_ARM_COPROC_SHIFT) | \ + ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \ + ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \ + ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \ + ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \ + ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT)) + +/* + * Convert a full 64 bit KVM register ID to the truncated 32 bit + * version used as a key for the coprocessor register hashtable + */ +static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid) +{ + uint32_t cpregid = kvmid; + if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) { + cpregid |= CP_REG_AA64_MASK; + } else { + if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { + cpregid |= (1 << 15); + } + + /* + * KVM is always non-secure so add the NS flag on AArch32 register + * entries. + */ + cpregid |= 1 << CP_REG_NS_SHIFT; + } + return cpregid; +} + +/* + * Convert a truncated 32 bit hashtable key into the full + * 64 bit KVM register ID. + */ +static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) +{ + uint64_t kvmid; + + if (cpregid & CP_REG_AA64_MASK) { + kvmid = cpregid & ~CP_REG_AA64_MASK; + kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64; + } else { + kvmid = cpregid & ~(1 << 15); + if (cpregid & (1 << 15)) { + kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM; + } else { + kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM; + } + } + return kvmid; +} + /* * Valid values for ARMCPRegInfo state field, indicating which of * the AArch32 and AArch64 execution states this register is visible in. diff --git a/target/arm/cpu.h b/target/arm/cpu.h index d623afe84a..12b1082537 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2559,97 +2559,6 @@ void arm_cpu_list(void); uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); -/* Interface for defining coprocessor registers. - * Registers are defined in tables of arm_cp_reginfo structs - * which are passed to define_arm_cp_regs(). - */ - -/* When looking up a coprocessor register we look for it - * via an integer which encodes all of: - * coprocessor number - * Crn, Crm, opc1, opc2 fields - * 32 or 64 bit register (ie is it accessed via MRC/MCR - * or via MRRC/MCRR?) - * non-secure/secure bank (AArch32 only) - * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field. - * (In this case crn and opc2 should be zero.) - * For AArch64, there is no 32/64 bit size distinction; - * instead all registers have a 2 bit op0, 3 bit op1 and op2, - * and 4 bit CRn and CRm. The encoding patterns are chosen - * to be easy to convert to and from the KVM encodings, and also - * so that the hashtable can contain both AArch32 and AArch64 - * registers (to allow for interprocessing where we might run - * 32 bit code on a 64 bit core). - */ -/* This bit is private to our hashtable cpreg; in KVM register - * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64 - * in the upper bits of the 64 bit ID. - */ -#define CP_REG_AA64_SHIFT 28 -#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT) - -/* To enable banking of coprocessor registers depending on ns-bit we - * add a bit to distinguish between secure and non-secure cpregs in the - * hashtable. - */ -#define CP_REG_NS_SHIFT 29 -#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT) - -#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \ - ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \ - ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2)) - -#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \ - (CP_REG_AA64_MASK | \ - ((cp) << CP_REG_ARM_COPROC_SHIFT) | \ - ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \ - ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \ - ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \ - ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \ - ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT)) - -/* Convert a full 64 bit KVM register ID to the truncated 32 bit - * version used as a key for the coprocessor register hashtable - */ -static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid) -{ - uint32_t cpregid = kvmid; - if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) { - cpregid |= CP_REG_AA64_MASK; - } else { - if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) { - cpregid |= (1 << 15); - } - - /* KVM is always non-secure so add the NS flag on AArch32 register - * entries. - */ - cpregid |= 1 << CP_REG_NS_SHIFT; - } - return cpregid; -} - -/* Convert a truncated 32 bit hashtable key into the full - * 64 bit KVM register ID. - */ -static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) -{ - uint64_t kvmid; - - if (cpregid & CP_REG_AA64_MASK) { - kvmid = cpregid & ~CP_REG_AA64_MASK; - kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64; - } else { - kvmid = cpregid & ~(1 << 15); - if (cpregid & (1 << 15)) { - kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM; - } else { - kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM; - } - } - return kvmid; -} - /* Return the highest implemented Exception Level */ static inline int arm_highest_el(CPUARMState *env) { From 5ad2d7a97cd9d1ed2527d888d343ee40f1b871f3 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:17 -0300 Subject: [PATCH 753/814] tests/avocado: Skip tests that require a missing accelerator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a test was tagged with the "accel" tag and the specified accelerator it not present in the qemu binary, cancel the test. We can now write tests without explicit calls to require_accelerator, just the tag is enough. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- tests/avocado/avocado_qemu/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 25a546842f..a313e88c07 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -274,6 +274,10 @@ class QemuSystemTest(QemuBaseTest): 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')) From 9bb9a3f3c80d57ef2abed12253a613315fd8be85 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:18 -0300 Subject: [PATCH 754/814] tests/avocado: Tag TCG tests with accel:tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the test to be skipped when TCG is not present in the QEMU binary. Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Tested-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- tests/avocado/boot_linux_console.py | 1 + tests/avocado/reverse_debugging.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index be60f8cda9..574609bf43 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -997,6 +997,7 @@ class BootLinuxConsole(LinuxKernelTest): def test_aarch64_raspi3_atf(self): """ + :avocado: tags=accel:tcg :avocado: tags=arch:aarch64 :avocado: tags=machine:raspi3b :avocado: tags=cpu:cortex-a53 diff --git a/tests/avocado/reverse_debugging.py b/tests/avocado/reverse_debugging.py index d2921e70c3..680c314cfc 100644 --- a/tests/avocado/reverse_debugging.py +++ b/tests/avocado/reverse_debugging.py @@ -173,6 +173,10 @@ class ReverseDebugging(LinuxKernelTest): vm.shutdown() class ReverseDebugging_X86_64(ReverseDebugging): + """ + :avocado: tags=accel:tcg + """ + REG_PC = 0x10 REG_CS = 0x12 def get_pc(self, g): @@ -190,6 +194,10 @@ class ReverseDebugging_X86_64(ReverseDebugging): self.reverse_debugging() class ReverseDebugging_AArch64(ReverseDebugging): + """ + :avocado: tags=accel:tcg + """ + REG_PC = 32 # unidentified gitlab timeout problem From 6c8a108dea3a79a8003e2783d984591c411714e4 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:21 -0300 Subject: [PATCH 755/814] target/arm: Use "max" as default cpu for the virt machine with KVM Now that the cortex-a15 is under CONFIG_TCG, use as default CPU for a KVM-only build the 'max' cpu. Note that we cannot use 'host' here because the qtests can run without any other accelerator (than qtest) and 'host' depends on KVM being enabled. Signed-off-by: Fabiano Rosas Acked-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Peter Maydell --- hw/arm/virt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8d13e4486b..ac626b3bef 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3013,7 +3013,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->minimum_page_bits = 12; mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = virt_cpu_index_to_props; +#ifdef CONFIG_TCG mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); +#else + mc->default_cpu_type = ARM_CPU_TYPE_NAME("max"); +#endif mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; mc->kvm_type = virt_kvm_type; assert(!mc->get_hotplug_handler); From 500a0accb5319df02c0385f877a37f7e2a2a0bb3 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:22 -0300 Subject: [PATCH 756/814] tests/qtest: arm-cpu-features: Match tests to required accelerators Signed-off-by: Fabiano Rosas Reviewed-by: Richard Henderson Acked-by: Thomas Huth Signed-off-by: Peter Maydell --- tests/qtest/arm-cpu-features.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index 8691802950..1cb08138ad 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -21,7 +21,7 @@ #define SVE_MAX_VQ 16 #define MACHINE "-machine virt,gic-version=max -accel tcg " -#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm -accel tcg " +#define MACHINE_KVM "-machine virt,gic-version=max -accel kvm " #define QUERY_HEAD "{ 'execute': 'query-cpu-model-expansion', " \ " 'arguments': { 'type': 'full', " #define QUERY_TAIL "}}" @@ -607,31 +607,39 @@ int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - qtest_add_data_func("/arm/query-cpu-model-expansion", - NULL, test_query_cpu_model_expansion); + if (qtest_has_accel("tcg")) { + qtest_add_data_func("/arm/query-cpu-model-expansion", + NULL, test_query_cpu_model_expansion); + } + + if (!g_str_equal(qtest_get_arch(), "aarch64")) { + goto out; + } /* * For now we only run KVM specific tests with AArch64 QEMU in * order avoid attempting to run an AArch32 QEMU with KVM on * AArch64 hosts. That won't work and isn't easy to detect. */ - if (g_str_equal(qtest_get_arch(), "aarch64") && qtest_has_accel("kvm")) { + if (qtest_has_accel("kvm")) { /* * This tests target the 'host' CPU type, so register it only if * KVM is available. */ qtest_add_data_func("/arm/kvm/query-cpu-model-expansion", NULL, test_query_cpu_model_expansion_kvm); - } - if (g_str_equal(qtest_get_arch(), "aarch64")) { - qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8", - NULL, sve_tests_sve_max_vq_8); - qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off", - NULL, sve_tests_sve_off); qtest_add_data_func("/arm/kvm/query-cpu-model-expansion/sve-off", NULL, sve_tests_sve_off_kvm); } + if (qtest_has_accel("tcg")) { + qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-max-vq-8", + NULL, sve_tests_sve_max_vq_8); + qtest_add_data_func("/arm/max/query-cpu-model-expansion/sve-off", + NULL, sve_tests_sve_off); + } + +out: return g_test_run(); } From caf01d6a435d9f4a95aeae2f9fc6cb8b889b1fb8 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 13 Feb 2023 17:29:23 -0300 Subject: [PATCH 757/814] tests/qtest: Restrict tpm-tis-devices-{swtpm}-test to CONFIG_TCG These tests set -accel tcg, so restrict them to when TCG is present. Signed-off-by: Fabiano Rosas Acked-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Peter Maydell --- tests/qtest/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 222e1892fb..29a4efb4c2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -208,8 +208,8 @@ qtests_arm = \ # TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional qtests_aarch64 = \ (cpu != 'arm' and unpack_edk2_blobs ? ['bios-tables-test'] : []) + \ - (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) + \ - (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ + (config_all.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \ + ['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \ (config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \ (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \ ['arm-cpu-features', From 5da7701e2a9f8454a24595857df7d24f7111645a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 15 Feb 2023 12:05:31 +0000 Subject: [PATCH 758/814] virtiofsd: Remove test Rmove the avocado test for virtiofsd, since we're about to remove the C implementation. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stefan Hajnoczi --- .../org.centos/stream/8/x86_64/test-avocado | 7 - tests/avocado/virtiofs_submounts.py | 217 ------------------ 2 files changed, 224 deletions(-) delete mode 100644 tests/avocado/virtiofs_submounts.py diff --git a/scripts/ci/org.centos/stream/8/x86_64/test-avocado b/scripts/ci/org.centos/stream/8/x86_64/test-avocado index 7aeecbcfb8..f403e4e7ec 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/test-avocado +++ b/scripts/ci/org.centos/stream/8/x86_64/test-avocado @@ -14,13 +14,6 @@ # * Require machine type "x-remote": # - tests/avocado/multiprocess.py:Multiprocess.test_multiprocess_x86_64 # -# * Needs superuser privileges: -# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_pre_virtiofsd_set_up -# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_pre_launch_set_up -# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_post_launch_set_up -# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_post_mount_set_up -# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_two_runs -# # * Requires display type "egl-headless": # - tests/avocado/virtio-gpu.py:VirtioGPUx86.test_virtio_vga_virgl # - tests/avocado/virtio-gpu.py:VirtioGPUx86.test_vhost_user_vga_virgl diff --git a/tests/avocado/virtiofs_submounts.py b/tests/avocado/virtiofs_submounts.py deleted file mode 100644 index e6dc32ffd4..0000000000 --- a/tests/avocado/virtiofs_submounts.py +++ /dev/null @@ -1,217 +0,0 @@ -import logging -import re -import os -import subprocess -import time - -from avocado import skipUnless -from avocado_qemu import LinuxTest, BUILD_DIR -from avocado_qemu import has_cmds -from avocado_qemu import run_cmd -from avocado_qemu import wait_for_console_pattern -from avocado.utils import ssh - - -class VirtiofsSubmountsTest(LinuxTest): - """ - :avocado: tags=arch:x86_64 - :avocado: tags=accel:kvm - """ - - def run(self, args, ignore_error=False): - stdout, stderr, ret = run_cmd(args) - - if ret != 0: - cmdline = ' '.join(args) - if not ignore_error: - self.fail(f'{cmdline}: Returned {ret}: {stderr}') - else: - self.log.warn(f'{cmdline}: Returned {ret}: {stderr}') - - return (stdout, stderr, ret) - - def set_up_shared_dir(self): - self.shared_dir = os.path.join(self.workdir, 'virtiofs-shared') - - os.mkdir(self.shared_dir) - - self.run(('cp', self.get_data('guest.sh'), - os.path.join(self.shared_dir, 'check.sh'))) - - self.run(('cp', self.get_data('guest-cleanup.sh'), - os.path.join(self.shared_dir, 'cleanup.sh'))) - - def set_up_virtiofs(self): - attmp = os.getenv('AVOCADO_TESTS_COMMON_TMPDIR') - self.vfsdsock = os.path.join(attmp, 'vfsdsock') - - self.run(('sudo', '-n', 'rm', '-f', self.vfsdsock), ignore_error=True) - - self.virtiofsd = \ - subprocess.Popen(('sudo', '-n', - 'tools/virtiofsd/virtiofsd', - f'--socket-path={self.vfsdsock}', - '-o', f'source={self.shared_dir}', - '-o', 'cache=always', - '-o', 'xattr', - '-o', 'announce_submounts', - '-f'), - stdout=subprocess.DEVNULL, - stderr=subprocess.PIPE, - universal_newlines=True) - - while not os.path.exists(self.vfsdsock): - if self.virtiofsd.poll() is not None: - self.fail('virtiofsd exited prematurely: ' + - self.virtiofsd.communicate()[1]) - time.sleep(0.1) - - self.run(('sudo', '-n', 'chmod', 'go+rw', self.vfsdsock)) - - self.vm.add_args('-chardev', - f'socket,id=vfsdsock,path={self.vfsdsock}', - '-device', - 'vhost-user-fs-pci,queue-size=1024,chardev=vfsdsock' \ - ',tag=host', - '-object', - 'memory-backend-file,id=mem,size=1G,' \ - 'mem-path=/dev/shm,share=on', - '-numa', - 'node,memdev=mem') - - def set_up_nested_mounts(self): - scratch_dir = os.path.join(self.shared_dir, 'scratch') - try: - os.mkdir(scratch_dir) - except FileExistsError: - pass - - args = ['bash', self.get_data('host.sh'), scratch_dir] - if self.seed: - args += [self.seed] - - out, _, _ = self.run(args) - seed = re.search(r'^Seed: \d+', out) - self.log.info(seed[0]) - - def mount_in_guest(self): - self.ssh_command('mkdir -p /mnt/host') - self.ssh_command('mount -t virtiofs host /mnt/host') - - def check_in_guest(self): - self.ssh_command('bash /mnt/host/check.sh /mnt/host/scratch/share') - - def live_cleanup(self): - self.ssh_command('bash /mnt/host/cleanup.sh /mnt/host/scratch') - - # It would be nice if the above was sufficient to make virtiofsd clear - # all references to the mounted directories (so they can be unmounted - # on the host), but unfortunately it is not. To do so, we have to - # resort to a remount. - self.ssh_command('mount -o remount /mnt/host') - - scratch_dir = os.path.join(self.shared_dir, 'scratch') - self.run(('bash', self.get_data('cleanup.sh'), scratch_dir)) - - @skipUnless(*has_cmds(('sudo -n', ('sudo', '-n', 'true')), - 'ssh-keygen', 'bash', 'losetup', 'mkfs.xfs', 'mount')) - def setUp(self): - vmlinuz = self.params.get('vmlinuz') - if vmlinuz is None: - """ - The Linux kernel supports FUSE auto-submounts only as of 5.10. - boot_linux.py currently provides Fedora 31, whose kernel is too - old, so this test cannot pass with the on-image kernel (you are - welcome to try, hence the option to force such a test with - -p vmlinuz=''). Therefore, for now the user must provide a - sufficiently new custom kernel, or effectively explicitly - request failure with -p vmlinuz=''. - Once an image with a sufficiently new kernel is available - (probably Fedora 34), we can make -p vmlinuz='' the default, so - that this parameter no longer needs to be specified. - """ - self.cancel('vmlinuz parameter not set; you must point it to a ' - 'Linux kernel binary to test (to run this test with ' \ - 'the on-image kernel, set it to an empty string)') - - self.seed = self.params.get('seed') - - self.ssh_key = os.path.join(self.workdir, 'id_ed25519') - - self.run(('ssh-keygen', '-N', '', '-t', 'ed25519', '-f', self.ssh_key)) - - pubkey = self.ssh_key + '.pub' - - super(VirtiofsSubmountsTest, self).setUp(pubkey) - - if vmlinuz: - self.vm.add_args('-kernel', vmlinuz, - '-append', 'console=ttyS0 root=/dev/sda1') - - self.require_accelerator("kvm") - self.vm.add_args('-accel', 'kvm') - - def tearDown(self): - try: - self.vm.shutdown() - except: - pass - - scratch_dir = os.path.join(self.shared_dir, 'scratch') - self.run(('bash', self.get_data('cleanup.sh'), scratch_dir), - ignore_error=True) - - def test_pre_virtiofsd_set_up(self): - self.set_up_shared_dir() - - self.set_up_nested_mounts() - - self.set_up_virtiofs() - self.launch_and_wait() - self.mount_in_guest() - self.check_in_guest() - - def test_pre_launch_set_up(self): - self.set_up_shared_dir() - self.set_up_virtiofs() - - self.set_up_nested_mounts() - - self.launch_and_wait() - self.mount_in_guest() - self.check_in_guest() - - def test_post_launch_set_up(self): - self.set_up_shared_dir() - self.set_up_virtiofs() - self.launch_and_wait() - - self.set_up_nested_mounts() - - self.mount_in_guest() - self.check_in_guest() - - def test_post_mount_set_up(self): - self.set_up_shared_dir() - self.set_up_virtiofs() - self.launch_and_wait() - self.mount_in_guest() - - self.set_up_nested_mounts() - - self.check_in_guest() - - def test_two_runs(self): - self.set_up_shared_dir() - - self.set_up_nested_mounts() - - self.set_up_virtiofs() - self.launch_and_wait() - self.mount_in_guest() - self.check_in_guest() - - self.live_cleanup() - self.set_up_nested_mounts() - - self.check_in_guest() From 8ab5e8a503b55eb27672777cfedea902bb22a246 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 18 Jan 2023 12:10:07 +0000 Subject: [PATCH 759/814] virtiofsd: Remove build and docs glue Remove all the virtiofsd build and docs infrastructure. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stefan Hajnoczi --- MAINTAINERS | 2 -- docs/conf.py | 4 ---- docs/meson.build | 1 - docs/tools/index.rst | 1 - meson.build | 1 - meson_options.txt | 2 -- .../ci/org.centos/stream/8/x86_64/configure | 2 -- scripts/coverity-scan/COMPONENTS.md | 3 --- scripts/meson-buildoptions.sh | 3 --- tools/meson.build | 13 ------------- tools/virtiofsd/50-qemu-virtiofsd.json.in | 5 ----- tools/virtiofsd/meson.build | 18 ------------------ 12 files changed, 55 deletions(-) delete mode 100644 tools/virtiofsd/50-qemu-virtiofsd.json.in delete mode 100644 tools/virtiofsd/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index fd54c1f140..5090ba0e49 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2096,10 +2096,8 @@ virtiofs M: Dr. David Alan Gilbert M: Stefan Hajnoczi S: Supported -F: tools/virtiofsd/* F: hw/virtio/vhost-user-fs* F: include/hw/virtio/vhost-user-fs.h -F: docs/tools/virtiofsd.rst L: virtio-fs@redhat.com virtio-input diff --git a/docs/conf.py b/docs/conf.py index 73a287a4f2..00767b0e24 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -290,10 +290,6 @@ man_pages = [ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper', 'QEMU 9p virtfs proxy filesystem helper', ['M. Mohan Kumar'], 1), - ('tools/virtiofsd', 'virtiofsd', - 'QEMU virtio-fs shared file system daemon', - ['Stefan Hajnoczi ', - 'Masayoshi Mizuma '], 1), ] man_make_section_directory = False diff --git a/docs/meson.build b/docs/meson.build index 9136fed3b7..bbcdccce68 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -48,7 +48,6 @@ if build_docs 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''), 'qemu-trace-stap.1': (stap.found() ? 'man1' : ''), 'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''), - 'virtiofsd.1': (have_virtiofsd ? 'man1' : ''), 'qemu.1': 'man1', 'qemu-block-drivers.7': 'man7', 'qemu-cpu-models.7': 'man7' diff --git a/docs/tools/index.rst b/docs/tools/index.rst index 2151adcf78..8e65ce0dfc 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -16,4 +16,3 @@ command line utilities and other standalone programs. qemu-pr-helper qemu-trace-stap virtfs-proxy-helper - virtiofsd diff --git a/meson.build b/meson.build index a76c855312..adfc0e28b5 100644 --- a/meson.build +++ b/meson.build @@ -3879,7 +3879,6 @@ if have_block summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')} summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS support': have_virtfs} - summary_info += {'build virtiofs daemon': have_virtiofsd} summary_info += {'Live block migration': config_host_data.get('CONFIG_LIVE_BLOCK_MIGRATION')} summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')} summary_info += {'bochs support': get_option('bochs').allowed()} diff --git a/meson_options.txt b/meson_options.txt index 7e5801db90..6b0900205e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -272,8 +272,6 @@ option('vhost_user_blk_server', type: 'feature', value: 'auto', description: 'build vhost-user-blk server') option('virtfs', type: 'feature', value: 'auto', description: 'virtio-9p support') -option('virtiofsd', type: 'feature', value: 'auto', - description: 'build virtiofs daemon (virtiofsd)') option('libvduse', type: 'feature', value: 'auto', description: 'build VDUSE Library') option('vduse_blk_export', type: 'feature', value: 'auto', diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure index 65eacf3c56..6e8983f39c 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/configure +++ b/scripts/ci/org.centos/stream/8/x86_64/configure @@ -138,7 +138,6 @@ --disable-vhost-vdpa \ --disable-virglrenderer \ --disable-virtfs \ ---disable-virtiofsd \ --disable-vnc \ --disable-vnc-jpeg \ --disable-png \ @@ -191,7 +190,6 @@ --enable-tpm \ --enable-trace-backends=dtrace \ --enable-usb-redir \ ---enable-virtiofsd \ --enable-vhost-kernel \ --enable-vhost-net \ --enable-vhost-user \ diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md index 0e6ab4936e..639dcee45a 100644 --- a/scripts/coverity-scan/COMPONENTS.md +++ b/scripts/coverity-scan/COMPONENTS.md @@ -132,9 +132,6 @@ util xen ~ (/qemu)?(.*/xen.*) -virtiofsd - ~ (/qemu)?(/tools/virtiofsd/.*) - (headers) ~ (/qemu)?(/include/.*) diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 939cc114dd..5d969a94c0 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -175,7 +175,6 @@ meson_options_help() { printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' printf "%s\n" ' virglrenderer virgl rendering support' printf "%s\n" ' virtfs virtio-9p support' - printf "%s\n" ' virtiofsd build virtiofs daemon (virtiofsd)' printf "%s\n" ' vmnet vmnet.framework network backend support' printf "%s\n" ' vnc VNC server' printf "%s\n" ' vnc-jpeg JPEG lossy compression for VNC server' @@ -461,8 +460,6 @@ _meson_option_parse() { --disable-virglrenderer) printf "%s" -Dvirglrenderer=disabled ;; --enable-virtfs) printf "%s" -Dvirtfs=enabled ;; --disable-virtfs) printf "%s" -Dvirtfs=disabled ;; - --enable-virtiofsd) printf "%s" -Dvirtiofsd=enabled ;; - --disable-virtiofsd) printf "%s" -Dvirtiofsd=disabled ;; --enable-vmnet) printf "%s" -Dvmnet=enabled ;; --disable-vmnet) printf "%s" -Dvmnet=disabled ;; --enable-vnc) printf "%s" -Dvnc=enabled ;; diff --git a/tools/meson.build b/tools/meson.build index 10eb3a043f..e69de29bb2 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -1,13 +0,0 @@ -have_virtiofsd = get_option('virtiofsd') \ - .require(targetos == 'linux', - error_message: 'virtiofsd requires Linux') \ - .require(seccomp.found() and libcap_ng.found(), - error_message: 'virtiofsd requires libcap-ng-devel and seccomp-devel') \ - .require(have_vhost_user, - error_message: 'virtiofsd needs vhost-user-support') \ - .disable_auto_if(not have_tools and not have_system) \ - .allowed() - -if have_virtiofsd - subdir('virtiofsd') -endif diff --git a/tools/virtiofsd/50-qemu-virtiofsd.json.in b/tools/virtiofsd/50-qemu-virtiofsd.json.in deleted file mode 100644 index 9bcd86f8dc..0000000000 --- a/tools/virtiofsd/50-qemu-virtiofsd.json.in +++ /dev/null @@ -1,5 +0,0 @@ -{ - "description": "QEMU virtiofsd vhost-user-fs", - "type": "fs", - "binary": "@libexecdir@/virtiofsd" -} diff --git a/tools/virtiofsd/meson.build b/tools/virtiofsd/meson.build deleted file mode 100644 index c134ba633f..0000000000 --- a/tools/virtiofsd/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -executable('virtiofsd', files( - 'buffer.c', - 'fuse_opt.c', - 'fuse_log.c', - 'fuse_lowlevel.c', - 'fuse_signals.c', - 'fuse_virtio.c', - 'helper.c', - 'passthrough_ll.c', - 'passthrough_seccomp.c'), - dependencies: [seccomp, qemuutil, libcap_ng, vhost_user], - install: true, - install_dir: get_option('libexecdir')) - -configure_file(input: '50-qemu-virtiofsd.json.in', - output: '50-qemu-virtiofsd.json', - configuration: { 'libexecdir' : get_option('prefix') / get_option('libexecdir') }, - install_dir: qemu_datadir / 'vhost-user') From e0dc2631ec4ac718ebe22ddea0ab25524eb37b0e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 18 Jan 2023 12:11:51 +0000 Subject: [PATCH 760/814] virtiofsd: Remove source Now remove all the source. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stefan Hajnoczi --- docs/tools/virtiofsd.rst | 403 --- tools/virtiofsd/buffer.c | 350 -- tools/virtiofsd/fuse_common.h | 837 ----- tools/virtiofsd/fuse_i.h | 107 - tools/virtiofsd/fuse_log.c | 40 - tools/virtiofsd/fuse_log.h | 75 - tools/virtiofsd/fuse_lowlevel.c | 2732 --------------- tools/virtiofsd/fuse_lowlevel.h | 1988 ----------- tools/virtiofsd/fuse_misc.h | 59 - tools/virtiofsd/fuse_opt.c | 446 --- tools/virtiofsd/fuse_opt.h | 272 -- tools/virtiofsd/fuse_signals.c | 93 - tools/virtiofsd/fuse_virtio.c | 1081 ------ tools/virtiofsd/fuse_virtio.h | 33 - tools/virtiofsd/helper.c | 409 --- tools/virtiofsd/passthrough_helpers.h | 51 - tools/virtiofsd/passthrough_ll.c | 4521 ------------------------- tools/virtiofsd/passthrough_seccomp.c | 182 - tools/virtiofsd/passthrough_seccomp.h | 14 - 19 files changed, 13693 deletions(-) delete mode 100644 docs/tools/virtiofsd.rst delete mode 100644 tools/virtiofsd/buffer.c delete mode 100644 tools/virtiofsd/fuse_common.h delete mode 100644 tools/virtiofsd/fuse_i.h delete mode 100644 tools/virtiofsd/fuse_log.c delete mode 100644 tools/virtiofsd/fuse_log.h delete mode 100644 tools/virtiofsd/fuse_lowlevel.c delete mode 100644 tools/virtiofsd/fuse_lowlevel.h delete mode 100644 tools/virtiofsd/fuse_misc.h delete mode 100644 tools/virtiofsd/fuse_opt.c delete mode 100644 tools/virtiofsd/fuse_opt.h delete mode 100644 tools/virtiofsd/fuse_signals.c delete mode 100644 tools/virtiofsd/fuse_virtio.c delete mode 100644 tools/virtiofsd/fuse_virtio.h delete mode 100644 tools/virtiofsd/helper.c delete mode 100644 tools/virtiofsd/passthrough_helpers.h delete mode 100644 tools/virtiofsd/passthrough_ll.c delete mode 100644 tools/virtiofsd/passthrough_seccomp.c delete mode 100644 tools/virtiofsd/passthrough_seccomp.h diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst deleted file mode 100644 index 995a754a7b..0000000000 --- a/docs/tools/virtiofsd.rst +++ /dev/null @@ -1,403 +0,0 @@ -QEMU virtio-fs shared file system daemon -======================================== - -Synopsis --------- - -**virtiofsd** [*OPTIONS*] - -Description ------------ - -Share a host directory tree with a guest through a virtio-fs device. This -program is a vhost-user backend that implements the virtio-fs device. Each -virtio-fs device instance requires its own virtiofsd process. - -This program is designed to work with QEMU's ``--device vhost-user-fs-pci`` -but should work with any virtual machine monitor (VMM) that supports -vhost-user. See the Examples section below. - -This program must be run as the root user. The program drops privileges where -possible during startup although it must be able to create and access files -with any uid/gid: - -* The ability to invoke syscalls is limited using seccomp(2). -* Linux capabilities(7) are dropped. - -In "namespace" sandbox mode the program switches into a new file system -namespace and invokes pivot_root(2) to make the shared directory tree its root. -A new pid and net namespace is also created to isolate the process. - -In "chroot" sandbox mode the program invokes chroot(2) to make the shared -directory tree its root. This mode is intended for container environments where -the container runtime has already set up the namespaces and the program does -not have permission to create namespaces itself. - -Both sandbox modes prevent "file system escapes" due to symlinks and other file -system objects that might lead to files outside the shared directory. - -Options -------- - -.. program:: virtiofsd - -.. option:: -h, --help - - Print help. - -.. option:: -V, --version - - Print version. - -.. option:: -d - - Enable debug output. - -.. option:: --syslog - - Print log messages to syslog instead of stderr. - -.. option:: -o OPTION - - * debug - - Enable debug output. - - * flock|no_flock - - Enable/disable flock. The default is ``no_flock``. - - * modcaps=CAPLIST - Modify the list of capabilities allowed; CAPLIST is a colon separated - list of capabilities, each preceded by either + or -, e.g. - ''+sys_admin:-chown''. - - * log_level=LEVEL - - Print only log messages matching LEVEL or more severe. LEVEL is one of - ``err``, ``warn``, ``info``, or ``debug``. The default is ``info``. - - * posix_lock|no_posix_lock - - Enable/disable remote POSIX locks. The default is ``no_posix_lock``. - - * readdirplus|no_readdirplus - - Enable/disable readdirplus. The default is ``readdirplus``. - - * sandbox=namespace|chroot - - Sandbox mode: - - namespace: Create mount, pid, and net namespaces and pivot_root(2) into - the shared directory. - - chroot: chroot(2) into shared directory (use in containers). - The default is "namespace". - - * source=PATH - - Share host directory tree located at PATH. This option is required. - - * timeout=TIMEOUT - - I/O timeout in seconds. The default depends on cache= option. - - * writeback|no_writeback - - Enable/disable writeback cache. The cache allows the FUSE client to buffer - and merge write requests. The default is ``no_writeback``. - - * xattr|no_xattr - - Enable/disable extended attributes (xattr) on files and directories. The - default is ``no_xattr``. - - * posix_acl|no_posix_acl - - Enable/disable posix acl support. Posix ACLs are disabled by default. - - * security_label|no_security_label - - Enable/disable security label support. Security labels are disabled by - default. This will allow client to send a MAC label of file during - file creation. Typically this is expected to be SELinux security - label. Server will try to set that label on newly created file - atomically wherever possible. - - * killpriv_v2|no_killpriv_v2 - - Enable/disable ``FUSE_HANDLE_KILLPRIV_V2`` support. KILLPRIV_V2 is enabled - by default as long as the client supports it. Enabling this option helps - with performance in write path. - -.. option:: --socket-path=PATH - - Listen on vhost-user UNIX domain socket at PATH. - -.. option:: --socket-group=GROUP - - Set the vhost-user UNIX domain socket gid to GROUP. - -.. option:: --fd=FDNUM - - Accept connections from vhost-user UNIX domain socket file descriptor FDNUM. - The file descriptor must already be listening for connections. - -.. option:: --thread-pool-size=NUM - - Restrict the number of worker threads per request queue to NUM. The default - is 0. - -.. option:: --cache=none|auto|always - - Select the desired trade-off between coherency and performance. ``none`` - forbids the FUSE client from caching to achieve best coherency at the cost of - performance. ``auto`` acts similar to NFS with a 1 second metadata cache - timeout. ``always`` sets a long cache lifetime at the expense of coherency. - The default is ``auto``. - -Extended attribute (xattr) mapping ----------------------------------- - -By default the name of xattr's used by the client are passed through to the server -file system. This can be a problem where either those xattr names are used -by something on the server (e.g. selinux client/server confusion) or if the -``virtiofsd`` is running in a container with restricted privileges where it -cannot access some attributes. - -Mapping syntax -~~~~~~~~~~~~~~ - -A mapping of xattr names can be made using -o xattrmap=mapping where the ``mapping`` -string consists of a series of rules. - -The first matching rule terminates the mapping. -The set of rules must include a terminating rule to match any remaining attributes -at the end. - -Each rule consists of a number of fields separated with a separator that is the -first non-white space character in the rule. This separator must then be used -for the whole rule. -White space may be added before and after each rule. - -Using ':' as the separator a rule is of the form: - -``:type:scope:key:prepend:`` - -**scope** is: - -- 'client' - match 'key' against a xattr name from the client for - setxattr/getxattr/removexattr -- 'server' - match 'prepend' against a xattr name from the server - for listxattr -- 'all' - can be used to make a single rule where both the server - and client matches are triggered. - -**type** is one of: - -- 'prefix' - is designed to prepend and strip a prefix; the modified - attributes then being passed on to the client/server. - -- 'ok' - Causes the rule set to be terminated when a match is found - while allowing matching xattr's through unchanged. - It is intended both as a way of explicitly terminating - the list of rules, and to allow some xattr's to skip following rules. - -- 'bad' - If a client tries to use a name matching 'key' it's - denied using EPERM; when the server passes an attribute - name matching 'prepend' it's hidden. In many ways it's use is very like - 'ok' as either an explicit terminator or for special handling of certain - patterns. - -- 'unsupported' - If a client tries to use a name matching 'key' it's - denied using ENOTSUP; when the server passes an attribute - name matching 'prepend' it's hidden. In many ways it's use is very like - 'ok' as either an explicit terminator or for special handling of certain - patterns. - -**key** is a string tested as a prefix on an attribute name originating -on the client. It maybe empty in which case a 'client' rule -will always match on client names. - -**prepend** is a string tested as a prefix on an attribute name originating -on the server, and used as a new prefix. It may be empty -in which case a 'server' rule will always match on all names from -the server. - -e.g.: - - ``:prefix:client:trusted.:user.virtiofs.:`` - - will match 'trusted.' attributes in client calls and prefix them before - passing them to the server. - - ``:prefix:server::user.virtiofs.:`` - - will strip 'user.virtiofs.' from all server replies. - - ``:prefix:all:trusted.:user.virtiofs.:`` - - combines the previous two cases into a single rule. - - ``:ok:client:user.::`` - - will allow get/set xattr for 'user.' xattr's and ignore - following rules. - - ``:ok:server::security.:`` - - will pass 'security.' xattr's in listxattr from the server - and ignore following rules. - - ``:ok:all:::`` - - will terminate the rule search passing any remaining attributes - in both directions. - - ``:bad:server::security.:`` - - would hide 'security.' xattr's in listxattr from the server. - -A simpler 'map' type provides a shorter syntax for the common case: - -``:map:key:prepend:`` - -The 'map' type adds a number of separate rules to add **prepend** as a prefix -to the matched **key** (or all attributes if **key** is empty). -There may be at most one 'map' rule and it must be the last rule in the set. - -Note: When the 'security.capability' xattr is remapped, the daemon has to do -extra work to remove it during many operations, which the host kernel normally -does itself. - -Security considerations -~~~~~~~~~~~~~~~~~~~~~~~ - -Operating systems typically partition the xattr namespace using -well defined name prefixes. Each partition may have different -access controls applied. For example, on Linux there are multiple -partitions - - * ``system.*`` - access varies depending on attribute & filesystem - * ``security.*`` - only processes with CAP_SYS_ADMIN - * ``trusted.*`` - only processes with CAP_SYS_ADMIN - * ``user.*`` - any process granted by file permissions / ownership - -While other OS such as FreeBSD have different name prefixes -and access control rules. - -When remapping attributes on the host, it is important to -ensure that the remapping does not allow a guest user to -evade the guest access control rules. - -Consider if ``trusted.*`` from the guest was remapped to -``user.virtiofs.trusted*`` in the host. An unprivileged -user in a Linux guest has the ability to write to xattrs -under ``user.*``. Thus the user can evade the access -control restriction on ``trusted.*`` by instead writing -to ``user.virtiofs.trusted.*``. - -As noted above, the partitions used and access controls -applied, will vary across guest OS, so it is not wise to -try to predict what the guest OS will use. - -The simplest way to avoid an insecure configuration is -to remap all xattrs at once, to a given fixed prefix. -This is shown in example (1) below. - -If selectively mapping only a subset of xattr prefixes, -then rules must be added to explicitly block direct -access to the target of the remapping. This is shown -in example (2) below. - -Mapping examples -~~~~~~~~~~~~~~~~ - -1) Prefix all attributes with 'user.virtiofs.' - -:: - - -o xattrmap=":prefix:all::user.virtiofs.::bad:all:::" - - -This uses two rules, using : as the field separator; -the first rule prefixes and strips 'user.virtiofs.', -the second rule hides any non-prefixed attributes that -the host set. - -This is equivalent to the 'map' rule: - -:: - - -o xattrmap=":map::user.virtiofs.:" - -2) Prefix 'trusted.' attributes, allow others through - -:: - - "/prefix/all/trusted./user.virtiofs./ - /bad/server//trusted./ - /bad/client/user.virtiofs.// - /ok/all///" - - -Here there are four rules, using / as the field -separator, and also demonstrating that new lines can -be included between rules. -The first rule is the prefixing of 'trusted.' and -stripping of 'user.virtiofs.'. -The second rule hides unprefixed 'trusted.' attributes -on the host. -The third rule stops a guest from explicitly setting -the 'user.virtiofs.' path directly to prevent access -control bypass on the target of the earlier prefix -remapping. -Finally, the fourth rule lets all remaining attributes -through. - -This is equivalent to the 'map' rule: - -:: - - -o xattrmap="/map/trusted./user.virtiofs./" - -3) Hide 'security.' attributes, and allow everything else - -:: - - "/bad/all/security./security./ - /ok/all///' - -The first rule combines what could be separate client and server -rules into a single 'all' rule, matching 'security.' in either -client arguments or lists returned from the host. This stops -the client seeing any 'security.' attributes on the server and -stops it setting any. - -SELinux support ---------------- -One can enable support for SELinux by running virtiofsd with option -"-o security_label". But this will try to save guest's security context -in xattr security.selinux on host and it might fail if host's SELinux -policy does not permit virtiofsd to do this operation. - -Hence, it is preferred to remap guest's "security.selinux" xattr to say -"trusted.virtiofs.security.selinux" on host. - -"-o xattrmap=:map:security.selinux:trusted.virtiofs.:" - -This will make sure that guest and host's SELinux xattrs on same file -remain separate and not interfere with each other. And will allow both -host and guest to implement their own separate SELinux policies. - -Setting trusted xattr on host requires CAP_SYS_ADMIN. So one will need -add this capability to daemon. - -"-o modcaps=+sys_admin" - -Giving CAP_SYS_ADMIN increases the risk on system. Now virtiofsd is more -powerful and if gets compromised, it can do lot of damage to host system. -So keep this trade-off in my mind while making a decision. - -Examples --------- - -Export ``/var/lib/fs/vm001/`` on vhost-user UNIX domain socket -``/var/run/vm001-vhost-fs.sock``: - -.. parsed-literal:: - - host# virtiofsd --socket-path=/var/run/vm001-vhost-fs.sock -o source=/var/lib/fs/vm001 - host# |qemu_system| \\ - -chardev socket,id=char0,path=/var/run/vm001-vhost-fs.sock \\ - -device vhost-user-fs-pci,chardev=char0,tag=myfs \\ - -object memory-backend-memfd,id=mem,size=4G,share=on \\ - -numa node,memdev=mem \\ - ... - guest# mount -t virtiofs myfs /mnt diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c deleted file mode 100644 index b5f04be356..0000000000 --- a/tools/virtiofsd/buffer.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2010 Miklos Szeredi - * - * Functions for dealing with `struct fuse_buf` and `struct - * fuse_bufvec`. - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "fuse_i.h" -#include "fuse_lowlevel.h" - -size_t fuse_buf_size(const struct fuse_bufvec *bufv) -{ - size_t i; - size_t size = 0; - - for (i = 0; i < bufv->count; i++) { - if (bufv->buf[i].size == SIZE_MAX) { - size = SIZE_MAX; - } else { - size += bufv->buf[i].size; - } - } - - return size; -} - -static ssize_t fuse_buf_writev(struct fuse_buf *out_buf, - struct fuse_bufvec *in_buf) -{ - ssize_t res, i, j; - size_t iovcnt = in_buf->count; - struct iovec *iov; - int fd = out_buf->fd; - - iov = g_try_new0(struct iovec, iovcnt); - if (!iov) { - return -ENOMEM; - } - - for (i = 0, j = 0; i < iovcnt; i++) { - /* Skip the buf with 0 size */ - if (in_buf->buf[i].size) { - iov[j].iov_base = in_buf->buf[i].mem; - iov[j].iov_len = in_buf->buf[i].size; - j++; - } - } - - if (out_buf->flags & FUSE_BUF_FD_SEEK) { - res = pwritev(fd, iov, iovcnt, out_buf->pos); - } else { - res = writev(fd, iov, iovcnt); - } - - if (res == -1) { - res = -errno; - } - - g_free(iov); - return res; -} - -static size_t min_size(size_t s1, size_t s2) -{ - return s1 < s2 ? s1 : s2; -} - -static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off, - const struct fuse_buf *src, size_t src_off, - size_t len) -{ - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (dst->flags & FUSE_BUF_FD_SEEK) { - res = pwrite(dst->fd, (char *)src->mem + src_off, len, - dst->pos + dst_off); - } else { - res = write(dst->fd, (char *)src->mem + src_off, len); - } - if (res == -1) { - if (!copied) { - return -errno; - } - break; - } - if (res == 0) { - break; - } - - copied += res; - if (!(dst->flags & FUSE_BUF_FD_RETRY)) { - break; - } - - src_off += res; - dst_off += res; - len -= res; - } - - return copied; -} - -static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off, - const struct fuse_buf *src, size_t src_off, - size_t len) -{ - ssize_t res = 0; - size_t copied = 0; - - while (len) { - if (src->flags & FUSE_BUF_FD_SEEK) { - res = pread(src->fd, (char *)dst->mem + dst_off, len, - src->pos + src_off); - } else { - res = read(src->fd, (char *)dst->mem + dst_off, len); - } - if (res == -1) { - if (!copied) { - return -errno; - } - break; - } - if (res == 0) { - break; - } - - copied += res; - if (!(src->flags & FUSE_BUF_FD_RETRY)) { - break; - } - - dst_off += res; - src_off += res; - len -= res; - } - - return copied; -} - -static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off, - const struct fuse_buf *src, size_t src_off, - size_t len) -{ - char buf[4096]; - struct fuse_buf tmp = { - .size = sizeof(buf), - .flags = 0, - }; - ssize_t res; - size_t copied = 0; - - tmp.mem = buf; - - while (len) { - size_t this_len = min_size(tmp.size, len); - size_t read_len; - - res = fuse_buf_read(&tmp, 0, src, src_off, this_len); - if (res < 0) { - if (!copied) { - return res; - } - break; - } - if (res == 0) { - break; - } - - read_len = res; - res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len); - if (res < 0) { - if (!copied) { - return res; - } - break; - } - if (res == 0) { - break; - } - - copied += res; - - if (res < this_len) { - break; - } - - dst_off += res; - src_off += res; - len -= res; - } - - return copied; -} - -static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off, - const struct fuse_buf *src, size_t src_off, - size_t len) -{ - int src_is_fd = src->flags & FUSE_BUF_IS_FD; - int dst_is_fd = dst->flags & FUSE_BUF_IS_FD; - - if (!src_is_fd && !dst_is_fd) { - char *dstmem = (char *)dst->mem + dst_off; - char *srcmem = (char *)src->mem + src_off; - - if (dstmem != srcmem) { - if (dstmem + len <= srcmem || srcmem + len <= dstmem) { - memcpy(dstmem, srcmem, len); - } else { - memmove(dstmem, srcmem, len); - } - } - - return len; - } else if (!src_is_fd) { - return fuse_buf_write(dst, dst_off, src, src_off, len); - } else if (!dst_is_fd) { - return fuse_buf_read(dst, dst_off, src, src_off, len); - } else { - return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); - } -} - -static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv) -{ - if (bufv->idx < bufv->count) { - return &bufv->buf[bufv->idx]; - } else { - return NULL; - } -} - -static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len) -{ - const struct fuse_buf *buf = fuse_bufvec_current(bufv); - - if (!buf) { - return 0; - } - - bufv->off += len; - assert(bufv->off <= buf->size); - if (bufv->off == buf->size) { - assert(bufv->idx < bufv->count); - bufv->idx++; - if (bufv->idx == bufv->count) { - return 0; - } - bufv->off = 0; - } - return 1; -} - -ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv) -{ - size_t copied = 0, i; - - if (dstv == srcv) { - return fuse_buf_size(dstv); - } - - /* - * use writev to improve bandwidth when all the - * src buffers already mapped by the daemon - * process - */ - for (i = 0; i < srcv->count; i++) { - if (srcv->buf[i].flags & FUSE_BUF_IS_FD) { - break; - } - } - if ((i == srcv->count) && (dstv->count == 1) && - (dstv->idx == 0) && - (dstv->buf[0].flags & FUSE_BUF_IS_FD)) { - dstv->buf[0].pos += dstv->off; - return fuse_buf_writev(&dstv->buf[0], srcv); - } - - for (;;) { - const struct fuse_buf *src = fuse_bufvec_current(srcv); - const struct fuse_buf *dst = fuse_bufvec_current(dstv); - size_t src_len; - size_t dst_len; - size_t len; - ssize_t res; - - if (src == NULL || dst == NULL) { - break; - } - - src_len = src->size - srcv->off; - dst_len = dst->size - dstv->off; - len = min_size(src_len, dst_len); - - res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len); - if (res < 0) { - if (!copied) { - return res; - } - break; - } - copied += res; - - if (!fuse_bufvec_advance(srcv, res) || - !fuse_bufvec_advance(dstv, res)) { - break; - } - - if (res < len) { - break; - } - } - - return copied; -} - -void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len) -{ - void *ptr; - - if (len > iter->size - iter->pos) { - return NULL; - } - - ptr = iter->mem + iter->pos; - iter->pos += len; - return ptr; -} - -const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter) -{ - const char *str = iter->mem + iter->pos; - size_t remaining = iter->size - iter->pos; - size_t i; - - for (i = 0; i < remaining; i++) { - if (str[i] == '\0') { - iter->pos += i + 1; - return str; - } - } - return NULL; -} diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h deleted file mode 100644 index bf46954dab..0000000000 --- a/tools/virtiofsd/fuse_common.h +++ /dev/null @@ -1,837 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB. - */ - -/** @file */ - -#if !defined(FUSE_H_) && !defined(FUSE_LOWLEVEL_H_) -#error \ - "Never include directly; use or instead." -#endif - -#ifndef FUSE_COMMON_H_ -#define FUSE_COMMON_H_ - -#include "fuse_log.h" -#include "fuse_opt.h" - -/** Major version of FUSE library interface */ -#define FUSE_MAJOR_VERSION 3 - -/** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 2 - -#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) -#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) - -/** - * Information about an open file. - * - * File Handles are created by the open, opendir, and create methods and closed - * by the release and releasedir methods. Multiple file handles may be - * concurrently open for the same file. Generally, a client will create one - * file handle per file descriptor, though in some cases multiple file - * descriptors can share a single file handle. - */ -struct fuse_file_info { - /** Open flags. Available in open() and release() */ - int flags; - - /* - * In case of a write operation indicates if this was caused - * by a delayed write from the page cache. If so, then the - * context's pid, uid, and gid fields will not be valid, and - * the *fh* value may not match the *fh* value that would - * have been sent with the corresponding individual write - * requests if write caching had been disabled. - */ - unsigned int writepage:1; - - /** Can be filled in by open, to use direct I/O on this file. */ - unsigned int direct_io:1; - - /* - * Can be filled in by open. It signals the kernel that any - * currently cached file data (ie., data that the filesystem - * provided the last time the file was open) need not be - * invalidated. Has no effect when set in other contexts (in - * particular it does nothing when set by opendir()). - */ - unsigned int keep_cache:1; - - /* - * Indicates a flush operation. Set in flush operation, also - * maybe set in highlevel lock operation and lowlevel release - * operation. - */ - unsigned int flush:1; - - /* - * Can be filled in by open, to indicate that the file is not - * seekable. - */ - unsigned int nonseekable:1; - - /* - * Indicates that flock locks for this file should be - * released. If set, lock_owner shall contain a valid value. - * May only be set in ->release(). - */ - unsigned int flock_release:1; - - /* - * Can be filled in by opendir. It signals the kernel to - * enable caching of entries returned by readdir(). Has no - * effect when set in other contexts (in particular it does - * nothing when set by open()). - */ - unsigned int cache_readdir:1; - - /* Indicates that suid/sgid bits should be removed upon write */ - unsigned int kill_priv:1; - - - /** Padding. Reserved for future use*/ - unsigned int padding:24; - unsigned int padding2:32; - - /* - * File handle id. May be filled in by filesystem in create, - * open, and opendir(). Available in most other file operations on the - * same file handle. - */ - uint64_t fh; - - /** Lock owner id. Available in locking operations and flush */ - uint64_t lock_owner; - - /* - * Requested poll events. Available in ->poll. Only set on kernels - * which support it. If unsupported, this field is set to zero. - */ - uint32_t poll_events; -}; - -/* - * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' - */ - -/** - * Indicates that the filesystem supports asynchronous read requests. - * - * If this capability is not requested/available, the kernel will - * ensure that there is at most one pending read request per - * file-handle at any time, and will attempt to order read requests by - * increasing offset. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_ASYNC_READ (1 << 0) - -/** - * Indicates that the filesystem supports "remote" locking. - * - * This feature is enabled by default when supported by the kernel, - * and if getlk() and setlk() handlers are implemented. - */ -#define FUSE_CAP_POSIX_LOCKS (1 << 1) - -/** - * Indicates that the filesystem supports the O_TRUNC open flag. If - * disabled, and an application specifies O_TRUNC, fuse first calls - * truncate() and then open() with O_TRUNC filtered out. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3) - -/** - * Indicates that the filesystem supports lookups of "." and "..". - * - * This feature is disabled by default. - */ -#define FUSE_CAP_EXPORT_SUPPORT (1 << 4) - -/** - * Indicates that the kernel should not apply the umask to the - * file mode on create operations. - * - * This feature is disabled by default. - */ -#define FUSE_CAP_DONT_MASK (1 << 6) - -/** - * Indicates that libfuse should try to use splice() when writing to - * the fuse device. This may improve performance. - * - * This feature is disabled by default. - */ -#define FUSE_CAP_SPLICE_WRITE (1 << 7) - -/** - * Indicates that libfuse should try to move pages instead of copying when - * writing to / reading from the fuse device. This may improve performance. - * - * This feature is disabled by default. - */ -#define FUSE_CAP_SPLICE_MOVE (1 << 8) - -/** - * Indicates that libfuse should try to use splice() when reading from - * the fuse device. This may improve performance. - * - * This feature is enabled by default when supported by the kernel and - * if the filesystem implements a write_buf() handler. - */ -#define FUSE_CAP_SPLICE_READ (1 << 9) - -/** - * If set, the calls to flock(2) will be emulated using POSIX locks and must - * then be handled by the filesystem's setlock() handler. - * - * If not set, flock(2) calls will be handled by the FUSE kernel module - * internally (so any access that does not go through the kernel cannot be taken - * into account). - * - * This feature is enabled by default when supported by the kernel and - * if the filesystem implements a flock() handler. - */ -#define FUSE_CAP_FLOCK_LOCKS (1 << 10) - -/** - * Indicates that the filesystem supports ioctl's on directories. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_IOCTL_DIR (1 << 11) - -/** - * Traditionally, while a file is open the FUSE kernel module only - * asks the filesystem for an update of the file's attributes when a - * client attempts to read beyond EOF. This is unsuitable for - * e.g. network filesystems, where the file contents may change - * without the kernel knowing about it. - * - * If this flag is set, FUSE will check the validity of the attributes - * on every read. If the attributes are no longer valid (i.e., if the - * *attr_timeout* passed to fuse_reply_attr() or set in `struct - * fuse_entry_param` has passed), it will first issue a `getattr` - * request. If the new mtime differs from the previous value, any - * cached file *contents* will be invalidated as well. - * - * This flag should always be set when available. If all file changes - * go through the kernel, *attr_timeout* should be set to a very large - * number to avoid unnecessary getattr() calls. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12) - -/** - * Indicates that the filesystem supports readdirplus. - * - * This feature is enabled by default when supported by the kernel and if the - * filesystem implements a readdirplus() handler. - */ -#define FUSE_CAP_READDIRPLUS (1 << 13) - -/** - * Indicates that the filesystem supports adaptive readdirplus. - * - * If FUSE_CAP_READDIRPLUS is not set, this flag has no effect. - * - * If FUSE_CAP_READDIRPLUS is set and this flag is not set, the kernel - * will always issue readdirplus() requests to retrieve directory - * contents. - * - * If FUSE_CAP_READDIRPLUS is set and this flag is set, the kernel - * will issue both readdir() and readdirplus() requests, depending on - * how much information is expected to be required. - * - * As of Linux 4.20, the algorithm is as follows: when userspace - * starts to read directory entries, issue a READDIRPLUS request to - * the filesystem. If any entry attributes have been looked up by the - * time userspace requests the next batch of entries continue with - * READDIRPLUS, otherwise switch to plain READDIR. This will reasult - * in eg plain "ls" triggering READDIRPLUS first then READDIR after - * that because it doesn't do lookups. "ls -l" should result in all - * READDIRPLUS, except if dentries are already cached. - * - * This feature is enabled by default when supported by the kernel and - * if the filesystem implements both a readdirplus() and a readdir() - * handler. - */ -#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14) - -/** - * Indicates that the filesystem supports asynchronous direct I/O submission. - * - * If this capability is not requested/available, the kernel will ensure that - * there is at most one pending read and one pending write request per direct - * I/O file-handle at any time. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_ASYNC_DIO (1 << 15) - -/** - * Indicates that writeback caching should be enabled. This means that - * individual write request may be buffered and merged in the kernel - * before they are send to the filesystem. - * - * This feature is disabled by default. - */ -#define FUSE_CAP_WRITEBACK_CACHE (1 << 16) - -/** - * Indicates support for zero-message opens. If this flag is set in - * the `capable` field of the `fuse_conn_info` structure, then the - * filesystem may return `ENOSYS` from the open() handler to indicate - * success. Further attempts to open files will be handled in the - * kernel. (If this flag is not set, returning ENOSYS will be treated - * as an error and signaled to the caller). - * - * Setting (or unsetting) this flag in the `want` field has *no - * effect*. - */ -#define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17) - -/** - * Indicates support for parallel directory operations. If this flag - * is unset, the FUSE kernel module will ensure that lookup() and - * readdir() requests are never issued concurrently for the same - * directory. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_PARALLEL_DIROPS (1 << 18) - -/** - * Indicates support for POSIX ACLs. - * - * If this feature is enabled, the kernel will cache and have - * responsibility for enforcing ACLs. ACL will be stored as xattrs and - * passed to userspace, which is responsible for updating the ACLs in - * the filesystem, keeping the file mode in sync with the ACL, and - * ensuring inheritance of default ACLs when new filesystem nodes are - * created. Note that this requires that the file system is able to - * parse and interpret the xattr representation of ACLs. - * - * Enabling this feature implicitly turns on the - * ``default_permissions`` mount option (even if it was not passed to - * mount(2)). - * - * This feature is disabled by default. - */ -#define FUSE_CAP_POSIX_ACL (1 << 19) - -/** - * Indicates that the filesystem is responsible for unsetting - * setuid and setgid bits when a file is written, truncated, or - * its owner is changed. - * - * This feature is enabled by default when supported by the kernel. - */ -#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20) - -/** - * Indicates support for zero-message opendirs. If this flag is set in - * the `capable` field of the `fuse_conn_info` structure, then the filesystem - * may return `ENOSYS` from the opendir() handler to indicate success. Further - * opendir and releasedir messages will be handled in the kernel. (If this - * flag is not set, returning ENOSYS will be treated as an error and signalled - * to the caller.) - * - * Setting (or unsetting) this flag in the `want` field has *no effect*. - */ -#define FUSE_CAP_NO_OPENDIR_SUPPORT (1 << 24) - -/** - * Indicates that the kernel supports the FUSE_ATTR_SUBMOUNT flag. - * - * Setting (or unsetting) this flag in the `want` field has *no effect*. - */ -#define FUSE_CAP_SUBMOUNTS (1 << 27) - -/** - * Indicates that the filesystem is responsible for clearing - * security.capability xattr and clearing setuid and setgid bits. Following - * are the rules. - * - clear "security.capability" on write, truncate and chown unconditionally - * - clear suid/sgid if following is true. Note, sgid is cleared only if - * group executable bit is set. - * o setattr has FATTR_SIZE and FATTR_KILL_SUIDGID set. - * o setattr has FATTR_UID or FATTR_GID - * o open has O_TRUNC and FUSE_OPEN_KILL_SUIDGID - * o create has O_TRUNC and FUSE_OPEN_KILL_SUIDGID flag set. - * o write has FUSE_WRITE_KILL_SUIDGID - */ -#define FUSE_CAP_HANDLE_KILLPRIV_V2 (1 << 28) - -/** - * Indicates that file server supports extended struct fuse_setxattr_in - */ -#define FUSE_CAP_SETXATTR_EXT (1 << 29) - -/** - * Indicates that file server supports creating file security context - */ -#define FUSE_CAP_SECURITY_CTX (1ULL << 32) - -/** - * Ioctl flags - * - * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine - * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed - * FUSE_IOCTL_RETRY: retry with new iovecs - * FUSE_IOCTL_DIR: is a directory - * - * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs - */ -#define FUSE_IOCTL_COMPAT (1 << 0) -#define FUSE_IOCTL_UNRESTRICTED (1 << 1) -#define FUSE_IOCTL_RETRY (1 << 2) -#define FUSE_IOCTL_DIR (1 << 4) - -#define FUSE_IOCTL_MAX_IOV 256 - -/** - * Connection information, passed to the ->init() method - * - * Some of the elements are read-write, these can be changed to - * indicate the value requested by the filesystem. The requested - * value must usually be smaller than the indicated value. - */ -struct fuse_conn_info { - /** - * Major version of the protocol (read-only) - */ - unsigned proto_major; - - /** - * Minor version of the protocol (read-only) - */ - unsigned proto_minor; - - /** - * Maximum size of the write buffer - */ - unsigned max_write; - - /** - * Maximum size of read requests. A value of zero indicates no - * limit. However, even if the filesystem does not specify a - * limit, the maximum size of read requests will still be - * limited by the kernel. - * - * NOTE: For the time being, the maximum size of read requests - * must be set both here *and* passed to fuse_session_new() - * using the ``-o max_read=`` mount option. At some point - * in the future, specifying the mount option will no longer - * be necessary. - */ - unsigned max_read; - - /** - * Maximum readahead - */ - unsigned max_readahead; - - /** - * Capability flags that the kernel supports (read-only) - */ - uint64_t capable; - - /** - * Capability flags that the filesystem wants to enable. - * - * libfuse attempts to initialize this field with - * reasonable default values before calling the init() handler. - */ - uint64_t want; - - /** - * Maximum number of pending "background" requests. A - * background request is any type of request for which the - * total number is not limited by other means. As of kernel - * 4.8, only two types of requests fall into this category: - * - * 1. Read-ahead requests - * 2. Asynchronous direct I/O requests - * - * Read-ahead requests are generated (if max_readahead is - * non-zero) by the kernel to preemptively fill its caches - * when it anticipates that userspace will soon read more - * data. - * - * Asynchronous direct I/O requests are generated if - * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large - * direct I/O request. In this case the kernel will internally - * split it up into multiple smaller requests and submit them - * to the filesystem concurrently. - * - * Note that the following requests are *not* background - * requests: writeback requests (limited by the kernel's - * flusher algorithm), regular (i.e., synchronous and - * buffered) userspace read/write requests (limited to one per - * thread), asynchronous read requests (Linux's io_submit(2) - * call actually blocks, so these are also limited to one per - * thread). - */ - unsigned max_background; - - /** - * Kernel congestion threshold parameter. If the number of pending - * background requests exceeds this number, the FUSE kernel module will - * mark the filesystem as "congested". This instructs the kernel to - * expect that queued requests will take some time to complete, and to - * adjust its algorithms accordingly (e.g. by putting a waiting thread - * to sleep instead of using a busy-loop). - */ - unsigned congestion_threshold; - - /** - * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible - * for updating mtime and ctime when write requests are received. The - * updated values are passed to the filesystem with setattr() requests. - * However, if the filesystem does not support the full resolution of - * the kernel timestamps (nanoseconds), the mtime and ctime values used - * by kernel and filesystem will differ (and result in an apparent - * change of times after a cache flush). - * - * To prevent this problem, this variable can be used to inform the - * kernel about the timestamp granularity supported by the file-system. - * The value should be power of 10. The default is 1, i.e. full - * nano-second resolution. Filesystems supporting only second resolution - * should set this to 1000000000. - */ - unsigned time_gran; - - /** - * For future use. - */ - unsigned reserved[22]; -}; - -struct fuse_session; -struct fuse_pollhandle; -struct fuse_conn_info_opts; - -/** - * This function parses several command-line options that can be used - * to override elements of struct fuse_conn_info. The pointer returned - * by this function should be passed to the - * fuse_apply_conn_info_opts() method by the file system's init() - * handler. - * - * Before using this function, think twice if you really want these - * parameters to be adjustable from the command line. In most cases, - * they should be determined by the file system internally. - * - * The following options are recognized: - * - * -o max_write=N sets conn->max_write - * -o max_readahead=N sets conn->max_readahead - * -o max_background=N sets conn->max_background - * -o congestion_threshold=N sets conn->congestion_threshold - * -o async_read sets FUSE_CAP_ASYNC_READ in conn->want - * -o sync_read unsets FUSE_CAP_ASYNC_READ in conn->want - * -o atomic_o_trunc sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want - * -o no_remote_lock Equivalent to -o - *no_remote_flock,no_remote_posix_lock -o no_remote_flock Unsets - *FUSE_CAP_FLOCK_LOCKS in conn->want -o no_remote_posix_lock Unsets - *FUSE_CAP_POSIX_LOCKS in conn->want -o [no_]splice_write (un-)sets - *FUSE_CAP_SPLICE_WRITE in conn->want -o [no_]splice_move (un-)sets - *FUSE_CAP_SPLICE_MOVE in conn->want -o [no_]splice_read (un-)sets - *FUSE_CAP_SPLICE_READ in conn->want -o [no_]auto_inval_data (un-)sets - *FUSE_CAP_AUTO_INVAL_DATA in conn->want -o readdirplus=no unsets - *FUSE_CAP_READDIRPLUS in conn->want -o readdirplus=yes sets - *FUSE_CAP_READDIRPLUS and unsets FUSE_CAP_READDIRPLUS_AUTO in conn->want -o - *readdirplus=auto sets FUSE_CAP_READDIRPLUS and FUSE_CAP_READDIRPLUS_AUTO - *in conn->want -o [no_]async_dio (un-)sets FUSE_CAP_ASYNC_DIO in - *conn->want -o [no_]writeback_cache (un-)sets FUSE_CAP_WRITEBACK_CACHE in - *conn->want -o time_gran=N sets conn->time_gran - * - * Known options will be removed from *args*, unknown options will be - * passed through unchanged. - * - * @param args argument vector (input+output) - * @return parsed options - **/ -struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args); - -/** - * This function applies the (parsed) parameters in *opts* to the - * *conn* pointer. It may modify the following fields: wants, - * max_write, max_readahead, congestion_threshold, max_background, - * time_gran. A field is only set (or unset) if the corresponding - * option has been explicitly set. - */ -void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, - struct fuse_conn_info *conn); - -/** - * Go into the background - * - * @param foreground if true, stay in the foreground - * @return 0 on success, -1 on failure - */ -int fuse_daemonize(int foreground); - -/** - * Get the version of the library - * - * @return the version - */ -int fuse_version(void); - -/** - * Get the full package version string of the library - * - * @return the package version - */ -const char *fuse_pkgversion(void); - -/** - * Destroy poll handle - * - * @param ph the poll handle - */ -void fuse_pollhandle_destroy(struct fuse_pollhandle *ph); - -/* - * Data buffer - */ - -/** - * Buffer flags - */ -enum fuse_buf_flags { - /** - * Buffer contains a file descriptor - * - * If this flag is set, the .fd field is valid, otherwise the - * .mem fields is valid. - */ - FUSE_BUF_IS_FD = (1 << 1), - - /** - * Seek on the file descriptor - * - * If this flag is set then the .pos field is valid and is - * used to seek to the given offset before performing - * operation on file descriptor. - */ - FUSE_BUF_FD_SEEK = (1 << 2), - - /** - * Retry operation on file descriptor - * - * If this flag is set then retry operation on file descriptor - * until .size bytes have been copied or an error or EOF is - * detected. - */ - FUSE_BUF_FD_RETRY = (1 << 3), -}; - -/** - * Single data buffer - * - * Generic data buffer for I/O, extended attributes, etc... Data may - * be supplied as a memory pointer or as a file descriptor - */ -struct fuse_buf { - /** - * Size of data in bytes - */ - size_t size; - - /** - * Buffer flags - */ - enum fuse_buf_flags flags; - - /** - * Memory pointer - * - * Used unless FUSE_BUF_IS_FD flag is set. - */ - void *mem; - - /** - * File descriptor - * - * Used if FUSE_BUF_IS_FD flag is set. - */ - int fd; - - /** - * File position - * - * Used if FUSE_BUF_FD_SEEK flag is set. - */ - off_t pos; -}; - -/** - * Data buffer vector - * - * An array of data buffers, each containing a memory pointer or a - * file descriptor. - * - * Allocate dynamically to add more than one buffer. - */ -struct fuse_bufvec { - /** - * Number of buffers in the array - */ - size_t count; - - /** - * Index of current buffer within the array - */ - size_t idx; - - /** - * Current offset within the current buffer - */ - size_t off; - - /** - * Array of buffers - */ - struct fuse_buf buf[1]; -}; - -/* Initialize bufvec with a single buffer of given size */ -#define FUSE_BUFVEC_INIT(size__) \ - ((struct fuse_bufvec){ /* .count= */ 1, \ - /* .idx = */ 0, \ - /* .off = */ 0, /* .buf = */ \ - { /* [0] = */ { \ - /* .size = */ (size__), \ - /* .flags = */ (enum fuse_buf_flags)0, \ - /* .mem = */ NULL, \ - /* .fd = */ -1, \ - /* .pos = */ 0, \ - } } }) - -/** - * Get total size of data in a fuse buffer vector - * - * @param bufv buffer vector - * @return size of data - */ -size_t fuse_buf_size(const struct fuse_bufvec *bufv); - -/** - * Copy data from one buffer vector to another - * - * @param dst destination buffer vector - * @param src source buffer vector - * @return actual number of bytes copied or -errno on error - */ -ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src); - -/** - * Memory buffer iterator - * - */ -struct fuse_mbuf_iter { - /** - * Data pointer - */ - void *mem; - - /** - * Total length, in bytes - */ - size_t size; - - /** - * Offset from start of buffer - */ - size_t pos; -}; - -/* Initialize memory buffer iterator from a fuse_buf */ -#define FUSE_MBUF_ITER_INIT(fbuf) \ - ((struct fuse_mbuf_iter){ \ - .mem = fbuf->mem, \ - .size = fbuf->size, \ - .pos = 0, \ - }) - -/** - * Consume bytes from a memory buffer iterator - * - * @param iter memory buffer iterator - * @param len number of bytes to consume - * @return pointer to start of consumed bytes or - * NULL if advancing beyond end of buffer - */ -void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len); - -/** - * Consume a NUL-terminated string from a memory buffer iterator - * - * @param iter memory buffer iterator - * @return pointer to the string or - * NULL if advancing beyond end of buffer or there is no NUL-terminator - */ -const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter); - -/* - * Signal handling - */ -/** - * Exit session on HUP, TERM and INT signals and ignore PIPE signal - * - * Stores session in a global variable. May only be called once per - * process until fuse_remove_signal_handlers() is called. - * - * Once either of the POSIX signals arrives, the signal handler calls - * fuse_session_exit(). - * - * @param se the session to exit - * @return 0 on success, -1 on failure - * - * See also: - * fuse_remove_signal_handlers() - */ -int fuse_set_signal_handlers(struct fuse_session *se); - -/** - * Restore default signal handlers - * - * Resets global session. After this fuse_set_signal_handlers() may - * be called again. - * - * @param se the same session as given in fuse_set_signal_handlers() - * - * See also: - * fuse_set_signal_handlers() - */ -void fuse_remove_signal_handlers(struct fuse_session *se); - -/* - * Compatibility stuff - */ - -#if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30 -#error only API version 30 or greater is supported -#endif - - -/* - * This interface uses 64 bit off_t. - * - * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags! - */ -QEMU_BUILD_BUG_ON(sizeof(off_t) != 8); - -#endif /* FUSE_COMMON_H_ */ diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h deleted file mode 100644 index a5572fa4ae..0000000000 --- a/tools/virtiofsd/fuse_i.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#ifndef FUSE_I_H -#define FUSE_I_H - -#define FUSE_USE_VERSION 31 -#include "fuse_lowlevel.h" - -struct fv_VuDev; -struct fv_QueueInfo; - -struct fuse_security_context { - const char *name; - uint32_t ctxlen; - const void *ctx; -}; - -struct fuse_req { - struct fuse_session *se; - uint64_t unique; - int ctr; - pthread_mutex_t lock; - struct fuse_ctx ctx; - struct fuse_chan *ch; - int interrupted; - unsigned int ioctl_64bit:1; - union { - struct { - uint64_t unique; - } i; - struct { - fuse_interrupt_func_t func; - void *data; - } ni; - } u; - struct fuse_req *next; - struct fuse_req *prev; - struct fuse_security_context secctx; -}; - -struct fuse_notify_req { - uint64_t unique; - void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t, - const void *, const struct fuse_buf *); - struct fuse_notify_req *next; - struct fuse_notify_req *prev; -}; - -struct fuse_session { - char *mountpoint; - volatile int exited; - int fd; - int debug; - int deny_others; - struct fuse_lowlevel_ops op; - int got_init; - struct cuse_data *cuse_data; - void *userdata; - uid_t owner; - struct fuse_conn_info conn; - struct fuse_req list; - struct fuse_req interrupts; - pthread_mutex_t lock; - pthread_rwlock_t init_rwlock; - int got_destroy; - int broken_splice_nonblock; - uint64_t notify_ctr; - struct fuse_notify_req notify_list; - size_t bufsize; - int error; - char *vu_socket_path; - char *vu_socket_group; - int vu_listen_fd; - int vu_socketfd; - struct fv_VuDev *virtio_dev; - int thread_pool_size; -}; - -struct fuse_chan { - pthread_mutex_t lock; - int ctr; - int fd; - struct fv_QueueInfo *qi; -}; - -int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, - int count); -void fuse_free_req(fuse_req_t req); - -void fuse_session_process_buf_int(struct fuse_session *se, - struct fuse_bufvec *bufv, - struct fuse_chan *ch); - - -#define FUSE_MAX_MAX_PAGES 256 -#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 - -/* room needed in buffer to accommodate header */ -#define FUSE_BUFFER_HEADER_SIZE 0x1000 - -#endif diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c deleted file mode 100644 index 2de3f48ee7..0000000000 --- a/tools/virtiofsd/fuse_log.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2019 Red Hat, Inc. - * - * Logging API. - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "fuse_log.h" - - -G_GNUC_PRINTF(2, 0) -static void default_log_func(__attribute__((unused)) enum fuse_log_level level, - const char *fmt, va_list ap) -{ - vfprintf(stderr, fmt, ap); -} - -static fuse_log_func_t log_func = default_log_func; - -void fuse_set_log_func(fuse_log_func_t func) -{ - if (!func) { - func = default_log_func; - } - - log_func = func; -} - -void fuse_log(enum fuse_log_level level, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - log_func(level, fmt, ap); - va_end(ap); -} diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h deleted file mode 100644 index e5c2967ab9..0000000000 --- a/tools/virtiofsd/fuse_log.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2019 Red Hat, Inc. - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB. - */ - -#ifndef FUSE_LOG_H_ -#define FUSE_LOG_H_ - -/** @file - * - * This file defines the logging interface of FUSE - */ - - -/** - * Log severity level - * - * These levels correspond to syslog(2) log levels since they are widely used. - */ -enum fuse_log_level { - FUSE_LOG_EMERG, - FUSE_LOG_ALERT, - FUSE_LOG_CRIT, - FUSE_LOG_ERR, - FUSE_LOG_WARNING, - FUSE_LOG_NOTICE, - FUSE_LOG_INFO, - FUSE_LOG_DEBUG -}; - -/** - * Log message handler function. - * - * This function must be thread-safe. It may be called from any libfuse - * function, including fuse_parse_cmdline() and other functions invoked before - * a FUSE filesystem is created. - * - * Install a custom log message handler function using fuse_set_log_func(). - * - * @param level log severity level - * @param fmt sprintf-style format string including newline - * @param ap format string arguments - */ -typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt, - va_list ap) - G_GNUC_PRINTF(2, 0); - -/** - * Install a custom log handler function. - * - * Log messages are emitted by libfuse functions to report errors and debug - * information. Messages are printed to stderr by default but this can be - * overridden by installing a custom log message handler function. - * - * The log message handler function is global and affects all FUSE filesystems - * created within this process. - * - * @param func a custom log message handler function or NULL to revert to - * the default - */ -void fuse_set_log_func(fuse_log_func_t func); - -/** - * Emit a log message - * - * @param level severity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc) - * @param fmt sprintf-style format string including newline - */ -void fuse_log(enum fuse_log_level level, const char *fmt, ...) - G_GNUC_PRINTF(2, 3); - -#endif /* FUSE_LOG_H_ */ diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c deleted file mode 100644 index 194a1b813b..0000000000 --- a/tools/virtiofsd/fuse_lowlevel.c +++ /dev/null @@ -1,2732 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * Implementation of (most of) the low-level FUSE API. The session loop - * functions are implemented in separate files. - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "fuse_i.h" -#include "standard-headers/linux/fuse.h" -#include "fuse_misc.h" -#include "fuse_opt.h" -#include "fuse_virtio.h" - -#include - -#define THREAD_POOL_SIZE 0 - -#define OFFSET_MAX 0x7fffffffffffffffLL - -struct fuse_pollhandle { - uint64_t kh; - struct fuse_session *se; -}; - -static size_t pagesize; - -static __attribute__((constructor)) void fuse_ll_init_pagesize(void) -{ - pagesize = getpagesize(); -} - -static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) -{ - *attr = (struct fuse_attr){ - .ino = stbuf->st_ino, - .mode = stbuf->st_mode, - .nlink = stbuf->st_nlink, - .uid = stbuf->st_uid, - .gid = stbuf->st_gid, - .rdev = stbuf->st_rdev, - .size = stbuf->st_size, - .blksize = stbuf->st_blksize, - .blocks = stbuf->st_blocks, - .atime = stbuf->st_atime, - .mtime = stbuf->st_mtime, - .ctime = stbuf->st_ctime, - .atimensec = ST_ATIM_NSEC(stbuf), - .mtimensec = ST_MTIM_NSEC(stbuf), - .ctimensec = ST_CTIM_NSEC(stbuf), - }; -} - -static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) -{ - stbuf->st_mode = attr->mode; - stbuf->st_uid = attr->uid; - stbuf->st_gid = attr->gid; - stbuf->st_size = attr->size; - stbuf->st_atime = attr->atime; - stbuf->st_mtime = attr->mtime; - stbuf->st_ctime = attr->ctime; - ST_ATIM_NSEC_SET(stbuf, attr->atimensec); - ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); - ST_CTIM_NSEC_SET(stbuf, attr->ctimensec); -} - -static size_t iov_length(const struct iovec *iov, size_t count) -{ - size_t seg; - size_t ret = 0; - - for (seg = 0; seg < count; seg++) { - ret += iov[seg].iov_len; - } - return ret; -} - -static void list_init_req(struct fuse_req *req) -{ - req->next = req; - req->prev = req; -} - -static void list_del_req(struct fuse_req *req) -{ - struct fuse_req *prev = req->prev; - struct fuse_req *next = req->next; - prev->next = next; - next->prev = prev; -} - -static void list_add_req(struct fuse_req *req, struct fuse_req *next) -{ - struct fuse_req *prev = next->prev; - req->next = next; - req->prev = prev; - prev->next = req; - next->prev = req; -} - -static void destroy_req(fuse_req_t req) -{ - pthread_mutex_destroy(&req->lock); - g_free(req); -} - -void fuse_free_req(fuse_req_t req) -{ - int ctr; - struct fuse_session *se = req->se; - - pthread_mutex_lock(&se->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - list_del_req(req); - ctr = --req->ctr; - req->ch = NULL; - pthread_mutex_unlock(&se->lock); - if (!ctr) { - destroy_req(req); - } -} - -static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se) -{ - struct fuse_req *req; - - req = g_try_new0(struct fuse_req, 1); - if (req == NULL) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n"); - } else { - req->se = se; - req->ctr = 1; - list_init_req(req); - fuse_mutex_init(&req->lock); - } - - return req; -} - -/* Send data. If *ch* is NULL, send via session master fd */ -static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int count) -{ - struct fuse_out_header *out = iov[0].iov_base; - - out->len = iov_length(iov, count); - if (out->unique == 0) { - fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error, - out->len); - } else if (out->error) { - fuse_log(FUSE_LOG_DEBUG, - " unique: %llu, error: %i (%s), outsize: %i\n", - (unsigned long long)out->unique, out->error, - strerror(-out->error), out->len); - } else { - fuse_log(FUSE_LOG_DEBUG, " unique: %llu, success, outsize: %i\n", - (unsigned long long)out->unique, out->len); - } - - if (fuse_lowlevel_is_virtio(se)) { - return virtio_send_msg(se, ch, iov, count); - } - - abort(); /* virtio should have taken it before here */ - return 0; -} - - -int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, - int count) -{ - struct fuse_out_header out = { - .unique = req->unique, - .error = error, - }; - - if (error <= -1000 || error > 0) { - fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error); - out.error = -ERANGE; - } - - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); - - return fuse_send_msg(req->se, req->ch, iov, count); -} - -static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, - int count) -{ - int res; - - res = fuse_send_reply_iov_nofree(req, error, iov, count); - fuse_free_req(req); - return res; -} - -static int send_reply(fuse_req_t req, int error, const void *arg, - size_t argsize) -{ - struct iovec iov[2]; - int count = 1; - if (argsize) { - iov[1].iov_base = (void *)arg; - iov[1].iov_len = argsize; - count++; - } - return send_reply_iov(req, error, iov, count); -} - -int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) -{ - g_autofree struct iovec *padded_iov = NULL; - - padded_iov = g_try_new(struct iovec, count + 1); - if (padded_iov == NULL) { - return fuse_reply_err(req, ENOMEM); - } - - memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); - count++; - - return send_reply_iov(req, 0, padded_iov, count); -} - - -/* - * 'buf` is allowed to be empty so that the proper size may be - * allocated by the caller - */ -size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, - const char *name, const struct stat *stbuf, off_t off) -{ - (void)req; - size_t namelen; - size_t entlen; - size_t entlen_padded; - struct fuse_dirent *dirent; - - namelen = strlen(name); - entlen = FUSE_NAME_OFFSET + namelen; - entlen_padded = FUSE_DIRENT_ALIGN(entlen); - - if ((buf == NULL) || (entlen_padded > bufsize)) { - return entlen_padded; - } - - dirent = (struct fuse_dirent *)buf; - dirent->ino = stbuf->st_ino; - dirent->off = off; - dirent->namelen = namelen; - dirent->type = (stbuf->st_mode & S_IFMT) >> 12; - memcpy(dirent->name, name, namelen); - memset(dirent->name + namelen, 0, entlen_padded - entlen); - - return entlen_padded; -} - -static void convert_statfs(const struct statvfs *stbuf, - struct fuse_kstatfs *kstatfs) -{ - *kstatfs = (struct fuse_kstatfs){ - .bsize = stbuf->f_bsize, - .frsize = stbuf->f_frsize, - .blocks = stbuf->f_blocks, - .bfree = stbuf->f_bfree, - .bavail = stbuf->f_bavail, - .files = stbuf->f_files, - .ffree = stbuf->f_ffree, - .namelen = stbuf->f_namemax, - }; -} - -static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) -{ - return send_reply(req, 0, arg, argsize); -} - -int fuse_reply_err(fuse_req_t req, int err) -{ - return send_reply(req, -err, NULL, 0); -} - -void fuse_reply_none(fuse_req_t req) -{ - fuse_free_req(req); -} - -static unsigned long calc_timeout_sec(double t) -{ - if (t > (double)ULONG_MAX) { - return ULONG_MAX; - } else if (t < 0.0) { - return 0; - } else { - return (unsigned long)t; - } -} - -static unsigned int calc_timeout_nsec(double t) -{ - double f = t - (double)calc_timeout_sec(t); - if (f < 0.0) { - return 0; - } else if (f >= 0.999999999) { - return 999999999; - } else { - return (unsigned int)(f * 1.0e9); - } -} - -static void fill_entry(struct fuse_entry_out *arg, - const struct fuse_entry_param *e) -{ - *arg = (struct fuse_entry_out){ - .nodeid = e->ino, - .generation = e->generation, - .entry_valid = calc_timeout_sec(e->entry_timeout), - .entry_valid_nsec = calc_timeout_nsec(e->entry_timeout), - .attr_valid = calc_timeout_sec(e->attr_timeout), - .attr_valid_nsec = calc_timeout_nsec(e->attr_timeout), - }; - convert_stat(&e->attr, &arg->attr); - - arg->attr.flags = e->attr_flags; -} - -/* - * `buf` is allowed to be empty so that the proper size may be - * allocated by the caller - */ -size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, - const char *name, - const struct fuse_entry_param *e, off_t off) -{ - (void)req; - size_t namelen; - size_t entlen; - size_t entlen_padded; - - namelen = strlen(name); - entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen; - entlen_padded = FUSE_DIRENT_ALIGN(entlen); - if ((buf == NULL) || (entlen_padded > bufsize)) { - return entlen_padded; - } - - struct fuse_direntplus *dp = (struct fuse_direntplus *)buf; - memset(&dp->entry_out, 0, sizeof(dp->entry_out)); - fill_entry(&dp->entry_out, e); - - struct fuse_dirent *dirent = &dp->dirent; - *dirent = (struct fuse_dirent){ - .ino = e->attr.st_ino, - .off = off, - .namelen = namelen, - .type = (e->attr.st_mode & S_IFMT) >> 12, - }; - memcpy(dirent->name, name, namelen); - memset(dirent->name + namelen, 0, entlen_padded - entlen); - - return entlen_padded; -} - -static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f) -{ - arg->fh = f->fh; - if (f->direct_io) { - arg->open_flags |= FOPEN_DIRECT_IO; - } - if (f->keep_cache) { - arg->open_flags |= FOPEN_KEEP_CACHE; - } - if (f->cache_readdir) { - arg->open_flags |= FOPEN_CACHE_DIR; - } - if (f->nonseekable) { - arg->open_flags |= FOPEN_NONSEEKABLE; - } -} - -int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) -{ - struct fuse_entry_out arg; - size_t size = sizeof(arg); - - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg, e); - return send_reply_ok(req, &arg, size); -} - -int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *f) -{ - char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)]; - size_t entrysize = sizeof(struct fuse_entry_out); - struct fuse_entry_out *earg = (struct fuse_entry_out *)buf; - struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize); - - memset(buf, 0, sizeof(buf)); - fill_entry(earg, e); - fill_open(oarg, f); - return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out)); -} - -int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout) -{ - struct fuse_attr_out arg; - size_t size = sizeof(arg); - - memset(&arg, 0, sizeof(arg)); - arg.attr_valid = calc_timeout_sec(attr_timeout); - arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); - convert_stat(attr, &arg.attr); - - return send_reply_ok(req, &arg, size); -} - -int fuse_reply_readlink(fuse_req_t req, const char *linkname) -{ - return send_reply_ok(req, linkname, strlen(linkname)); -} - -int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) -{ - struct fuse_open_out arg; - - memset(&arg, 0, sizeof(arg)); - fill_open(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_write(fuse_req_t req, size_t count) -{ - struct fuse_write_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.size = count; - - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) -{ - return send_reply_ok(req, buf, size); -} - -static int fuse_send_data_iov_fallback(struct fuse_session *se, - struct fuse_chan *ch, struct iovec *iov, - int iov_count, struct fuse_bufvec *buf, - size_t len) -{ - /* Optimize common case */ - if (buf->count == 1 && buf->idx == 0 && buf->off == 0 && - !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { - /* - * FIXME: also avoid memory copy if there are multiple buffers - * but none of them contain an fd - */ - - iov[iov_count].iov_base = buf->buf[0].mem; - iov[iov_count].iov_len = len; - iov_count++; - return fuse_send_msg(se, ch, iov, iov_count); - } - - if (fuse_lowlevel_is_virtio(se) && buf->count == 1 && - buf->buf[0].flags == (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK)) { - return virtio_send_data_iov(se, ch, iov, iov_count, buf, len); - } - - abort(); /* Will have taken vhost path */ - return 0; -} - -static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int iov_count, - struct fuse_bufvec *buf) -{ - size_t len = fuse_buf_size(buf); - - return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len); -} - -int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv) -{ - struct iovec iov[2]; - struct fuse_out_header out = { - .unique = req->unique, - }; - int res; - - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); - - res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv); - if (res <= 0) { - fuse_free_req(req); - return res; - } else { - return fuse_reply_err(req, res); - } -} - -int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) -{ - struct fuse_statfs_out arg; - size_t size = sizeof(arg); - - memset(&arg, 0, sizeof(arg)); - convert_statfs(stbuf, &arg.st); - - return send_reply_ok(req, &arg, size); -} - -int fuse_reply_xattr(fuse_req_t req, size_t count) -{ - struct fuse_getxattr_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.size = count; - - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_lock(fuse_req_t req, const struct flock *lock) -{ - struct fuse_lk_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.lk.type = lock->l_type; - if (lock->l_type != F_UNLCK) { - arg.lk.start = lock->l_start; - if (lock->l_len == 0) { - arg.lk.end = OFFSET_MAX; - } else { - arg.lk.end = lock->l_start + lock->l_len - 1; - } - } - arg.lk.pid = lock->l_pid; - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_bmap(fuse_req_t req, uint64_t idx) -{ - struct fuse_bmap_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.block = idx; - - return send_reply_ok(req, &arg, sizeof(arg)); -} - -static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov, - size_t count) -{ - struct fuse_ioctl_iovec *fiov; - size_t i; - - fiov = g_try_new(struct fuse_ioctl_iovec, count); - if (!fiov) { - return NULL; - } - - for (i = 0; i < count; i++) { - fiov[i].base = (uintptr_t)iov[i].iov_base; - fiov[i].len = iov[i].iov_len; - } - - return fiov; -} - -int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, - size_t in_count, const struct iovec *out_iov, - size_t out_count) -{ - struct fuse_ioctl_out arg; - g_autofree struct fuse_ioctl_iovec *in_fiov = NULL; - g_autofree struct fuse_ioctl_iovec *out_fiov = NULL; - struct iovec iov[4]; - size_t count = 1; - - memset(&arg, 0, sizeof(arg)); - arg.flags |= FUSE_IOCTL_RETRY; - arg.in_iovs = in_count; - arg.out_iovs = out_count; - iov[count].iov_base = &arg; - iov[count].iov_len = sizeof(arg); - count++; - - /* Can't handle non-compat 64bit ioctls on 32bit */ - if (sizeof(void *) == 4 && req->ioctl_64bit) { - return fuse_reply_err(req, EINVAL); - } - - if (in_count) { - in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); - if (!in_fiov) { - return fuse_reply_err(req, ENOMEM); - } - - iov[count].iov_base = (void *)in_fiov; - iov[count].iov_len = sizeof(in_fiov[0]) * in_count; - count++; - } - if (out_count) { - out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); - if (!out_fiov) { - return fuse_reply_err(req, ENOMEM); - } - - iov[count].iov_base = (void *)out_fiov; - iov[count].iov_len = sizeof(out_fiov[0]) * out_count; - count++; - } - - return send_reply_iov(req, 0, iov, count); -} - -int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) -{ - struct fuse_ioctl_out arg; - struct iovec iov[3]; - size_t count = 1; - - memset(&arg, 0, sizeof(arg)); - arg.result = result; - iov[count].iov_base = &arg; - iov[count].iov_len = sizeof(arg); - count++; - - if (size) { - iov[count].iov_base = (char *)buf; - iov[count].iov_len = size; - count++; - } - - return send_reply_iov(req, 0, iov, count); -} - -int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, - int count) -{ - g_autofree struct iovec *padded_iov = NULL; - struct fuse_ioctl_out arg; - - padded_iov = g_try_new(struct iovec, count + 2); - if (padded_iov == NULL) { - return fuse_reply_err(req, ENOMEM); - } - - memset(&arg, 0, sizeof(arg)); - arg.result = result; - padded_iov[1].iov_base = &arg; - padded_iov[1].iov_len = sizeof(arg); - - memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); - - return send_reply_iov(req, 0, padded_iov, count + 2); -} - -int fuse_reply_poll(fuse_req_t req, unsigned revents) -{ - struct fuse_poll_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.revents = revents; - - return send_reply_ok(req, &arg, sizeof(arg)); -} - -int fuse_reply_lseek(fuse_req_t req, off_t off) -{ - struct fuse_lseek_out arg; - - memset(&arg, 0, sizeof(arg)); - arg.offset = off; - - return send_reply_ok(req, &arg, sizeof(arg)); -} - -static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - const char *name = fuse_mbuf_iter_advance_str(iter); - if (!name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.lookup) { - req->se->op.lookup(req, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_forget(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_forget_in *arg; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.forget) { - req->se->op.forget(req, nodeid, arg->nlookup); - } else { - fuse_reply_none(req); - } -} - -static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_batch_forget_in *arg; - struct fuse_forget_data *forgets; - size_t scount; - - (void)nodeid; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_none(req); - return; - } - - /* - * Prevent integer overflow. The compiler emits the following warning - * unless we use the scount local variable: - * - * error: comparison is always false due to limited range of data type - * [-Werror=type-limits] - * - * This may be true on 64-bit hosts but we need this check for 32-bit - * hosts. - */ - scount = arg->count; - if (scount > SIZE_MAX / sizeof(forgets[0])) { - fuse_reply_none(req); - return; - } - - forgets = fuse_mbuf_iter_advance(iter, arg->count * sizeof(forgets[0])); - if (!forgets) { - fuse_reply_none(req); - return; - } - - if (req->se->op.forget_multi) { - req->se->op.forget_multi(req, arg->count, forgets); - } else if (req->se->op.forget) { - unsigned int i; - - for (i = 0; i < arg->count; i++) { - struct fuse_req *dummy_req; - - dummy_req = fuse_ll_alloc_req(req->se); - if (dummy_req == NULL) { - break; - } - - dummy_req->unique = req->unique; - dummy_req->ctx = req->ctx; - dummy_req->ch = NULL; - - req->se->op.forget(dummy_req, forgets[i].ino, forgets[i].nlookup); - } - fuse_reply_none(req); - } else { - fuse_reply_none(req); - } -} - -static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_file_info *fip = NULL; - struct fuse_file_info fi; - - struct fuse_getattr_in *arg; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - if (arg->getattr_flags & FUSE_GETATTR_FH) { - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fip = &fi; - } - - if (req->se->op.getattr) { - req->se->op.getattr(req, nodeid, fip); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - if (req->se->op.setattr) { - struct fuse_setattr_in *arg; - struct fuse_file_info *fi = NULL; - struct fuse_file_info fi_store; - struct stat stbuf; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&stbuf, 0, sizeof(stbuf)); - convert_attr(arg, &stbuf); - if (arg->valid & FATTR_FH) { - arg->valid &= ~FATTR_FH; - memset(&fi_store, 0, sizeof(fi_store)); - fi = &fi_store; - fi->fh = arg->fh; - } - arg->valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID | - FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE | - FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME | - FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW | - FUSE_SET_ATTR_CTIME | FUSE_SET_ATTR_KILL_SUIDGID; - - req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_access(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_access_in *arg; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.access) { - req->se->op.access(req, nodeid, arg->mask); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - (void)iter; - - if (req->se->op.readlink) { - req->se->op.readlink(req, nodeid); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static int parse_secctx_fill_req(fuse_req_t req, struct fuse_mbuf_iter *iter) -{ - struct fuse_secctx_header *fsecctx_header; - struct fuse_secctx *fsecctx; - const void *secctx; - const char *name; - - fsecctx_header = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx_header)); - if (!fsecctx_header) { - return -EINVAL; - } - - /* - * As of now maximum of one security context is supported. It can - * change in future though. - */ - if (fsecctx_header->nr_secctx > 1) { - return -EINVAL; - } - - /* No security context sent. Maybe no LSM supports it */ - if (!fsecctx_header->nr_secctx) { - return 0; - } - - fsecctx = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx)); - if (!fsecctx) { - return -EINVAL; - } - - /* struct fsecctx with zero sized context is not expected */ - if (!fsecctx->size) { - return -EINVAL; - } - name = fuse_mbuf_iter_advance_str(iter); - if (!name) { - return -EINVAL; - } - - secctx = fuse_mbuf_iter_advance(iter, fsecctx->size); - if (!secctx) { - return -EINVAL; - } - - req->secctx.name = name; - req->secctx.ctx = secctx; - req->secctx.ctxlen = fsecctx->size; - return 0; -} - -static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_mknod_in *arg; - const char *name; - bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; - int err; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - name = fuse_mbuf_iter_advance_str(iter); - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - req->ctx.umask = arg->umask; - - if (secctx_enabled) { - err = parse_secctx_fill_req(req, iter); - if (err) { - fuse_reply_err(req, -err); - return; - } - } - - if (req->se->op.mknod) { - req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_mkdir_in *arg; - const char *name; - bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; - int err; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - name = fuse_mbuf_iter_advance_str(iter); - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - req->ctx.umask = arg->umask; - - if (secctx_enabled) { - err = parse_secctx_fill_req(req, iter); - if (err) { - fuse_reply_err(req, err); - return; - } - } - - if (req->se->op.mkdir) { - req->se->op.mkdir(req, nodeid, name, arg->mode); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - const char *name = fuse_mbuf_iter_advance_str(iter); - - if (!name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.unlink) { - req->se->op.unlink(req, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - const char *name = fuse_mbuf_iter_advance_str(iter); - - if (!name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.rmdir) { - req->se->op.rmdir(req, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - const char *name = fuse_mbuf_iter_advance_str(iter); - const char *linkname = fuse_mbuf_iter_advance_str(iter); - bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; - int err; - - if (!name || !linkname) { - fuse_reply_err(req, EINVAL); - return; - } - - if (secctx_enabled) { - err = parse_secctx_fill_req(req, iter); - if (err) { - fuse_reply_err(req, err); - return; - } - } - - if (req->se->op.symlink) { - req->se->op.symlink(req, linkname, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_rename(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_rename_in *arg; - const char *oldname; - const char *newname; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - oldname = fuse_mbuf_iter_advance_str(iter); - newname = fuse_mbuf_iter_advance_str(iter); - if (!arg || !oldname || !newname) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.rename) { - req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_rename2_in *arg; - const char *oldname; - const char *newname; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - oldname = fuse_mbuf_iter_advance_str(iter); - newname = fuse_mbuf_iter_advance_str(iter); - if (!arg || !oldname || !newname) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.rename) { - req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, - arg->flags); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_link(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_link_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - const char *name = fuse_mbuf_iter_advance_str(iter); - - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.link) { - req->se->op.link(req, arg->oldnodeid, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_create(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; - - if (req->se->op.create) { - struct fuse_create_in *arg; - struct fuse_file_info fi; - const char *name; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - name = fuse_mbuf_iter_advance_str(iter); - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (secctx_enabled) { - int err; - err = parse_secctx_fill_req(req, iter); - if (err) { - fuse_reply_err(req, err); - return; - } - } - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.kill_priv = arg->open_flags & FUSE_OPEN_KILL_SUIDGID; - - req->ctx.umask = arg->umask; - - req->se->op.create(req, nodeid, name, arg->mode, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_open(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_open_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - /* File creation is handled by do_create() or do_mknod() */ - if (arg->flags & (O_CREAT | O_TMPFILE)) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.kill_priv = arg->open_flags & FUSE_OPEN_KILL_SUIDGID; - - if (req->se->op.open) { - req->se->op.open(req, nodeid, &fi); - } else { - fuse_reply_open(req, &fi); - } -} - -static void do_read(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - if (req->se->op.read) { - struct fuse_read_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - req->se->op.read(req, nodeid, arg->size, arg->offset, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_write(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_write_in *arg; - struct fuse_file_info fi; - const char *param; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - param = fuse_mbuf_iter_advance(iter, arg->size); - if (!param) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0; - fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV); - - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - - if (req->se->op.write) { - req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter, struct fuse_bufvec *ibufv) -{ - struct fuse_session *se = req->se; - struct fuse_bufvec *pbufv = ibufv; - struct fuse_bufvec tmpbufv = { - .buf[0] = ibufv->buf[0], - .count = 1, - }; - struct fuse_write_in *arg; - size_t arg_size = sizeof(*arg); - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - - arg = fuse_mbuf_iter_advance(iter, arg_size); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - fi.lock_owner = arg->lock_owner; - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.writepage = !!(arg->write_flags & FUSE_WRITE_CACHE); - fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV); - - if (ibufv->count == 1) { - assert(!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD)); - tmpbufv.buf[0].mem = ((char *)arg) + arg_size; - tmpbufv.buf[0].size -= sizeof(struct fuse_in_header) + arg_size; - pbufv = &tmpbufv; - } else { - /* - * Input bufv contains the headers in the first element - * and the data in the rest, we need to skip that first element - */ - ibufv->buf[0].size = 0; - } - - if (fuse_buf_size(pbufv) != arg->size) { - fuse_log(FUSE_LOG_ERR, - "fuse: do_write_buf: buffer size doesn't match arg->size\n"); - fuse_reply_err(req, EIO); - return; - } - - se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi); -} - -static void do_flush(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_flush_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.flush = 1; - fi.lock_owner = arg->lock_owner; - - if (req->se->op.flush) { - req->se->op.flush(req, nodeid, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_release(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_release_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; - fi.lock_owner = arg->lock_owner; - - if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { - fi.flock_release = 1; - } - - if (req->se->op.release) { - req->se->op.release(req, nodeid, &fi); - } else { - fuse_reply_err(req, 0); - } -} - -static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_fsync_in *arg; - struct fuse_file_info fi; - int datasync; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - datasync = arg->fsync_flags & 1; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.fsync) { - if (fi.fh == (uint64_t)-1) { - req->se->op.fsync(req, nodeid, datasync, NULL); - } else { - req->se->op.fsync(req, nodeid, datasync, &fi); - } - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_open_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - - if (req->se->op.opendir) { - req->se->op.opendir(req, nodeid, &fi); - } else { - fuse_reply_open(req, &fi); - } -} - -static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_read_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.readdir) { - req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_read_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.readdirplus) { - req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_release_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - - if (req->se->op.releasedir) { - req->se->op.releasedir(req, nodeid, &fi); - } else { - fuse_reply_err(req, 0); - } -} - -static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_fsync_in *arg; - struct fuse_file_info fi; - int datasync; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - datasync = arg->fsync_flags & 1; - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.fsyncdir) { - req->se->op.fsyncdir(req, nodeid, datasync, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - (void)nodeid; - (void)iter; - - if (req->se->op.statfs) { - req->se->op.statfs(req, nodeid); - } else { - struct statvfs buf = { - .f_namemax = 255, - .f_bsize = 512, - }; - fuse_reply_statfs(req, &buf); - } -} - -static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_setxattr_in *arg; - const char *name; - const char *value; - bool setxattr_ext = req->se->conn.want & FUSE_CAP_SETXATTR_EXT; - - if (setxattr_ext) { - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - } else { - arg = fuse_mbuf_iter_advance(iter, FUSE_COMPAT_SETXATTR_IN_SIZE); - } - name = fuse_mbuf_iter_advance_str(iter); - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - value = fuse_mbuf_iter_advance(iter, arg->size); - if (!value) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.setxattr) { - uint32_t setxattr_flags = setxattr_ext ? arg->setxattr_flags : 0; - req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags, - setxattr_flags); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_getxattr_in *arg; - const char *name; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - name = fuse_mbuf_iter_advance_str(iter); - if (!arg || !name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.getxattr) { - req->se->op.getxattr(req, nodeid, name, arg->size); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_getxattr_in *arg; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.listxattr) { - req->se->op.listxattr(req, nodeid, arg->size); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - const char *name = fuse_mbuf_iter_advance_str(iter); - - if (!name) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.removexattr) { - req->se->op.removexattr(req, nodeid, name); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void convert_fuse_file_lock(struct fuse_file_lock *fl, - struct flock *flock) -{ - memset(flock, 0, sizeof(struct flock)); - flock->l_type = fl->type; - flock->l_whence = SEEK_SET; - flock->l_start = fl->start; - if (fl->end == OFFSET_MAX) { - flock->l_len = 0; - } else { - flock->l_len = fl->end - fl->start + 1; - } - flock->l_pid = fl->pid; -} - -static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_lk_in *arg; - struct fuse_file_info fi; - struct flock flock; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; - - convert_fuse_file_lock(&arg->lk, &flock); - if (req->se->op.getlk) { - req->se->op.getlk(req, nodeid, &fi, &flock); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter, int sleep) -{ - struct fuse_lk_in *arg; - struct fuse_file_info fi; - struct flock flock; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; - - if (arg->lk_flags & FUSE_LK_FLOCK) { - int op = 0; - - switch (arg->lk.type) { - case F_RDLCK: - op = LOCK_SH; - break; - case F_WRLCK: - op = LOCK_EX; - break; - case F_UNLCK: - op = LOCK_UN; - break; - } - if (!sleep) { - op |= LOCK_NB; - } - - if (req->se->op.flock) { - req->se->op.flock(req, nodeid, &fi, op); - } else { - fuse_reply_err(req, ENOSYS); - } - } else { - convert_fuse_file_lock(&arg->lk, &flock); - if (req->se->op.setlk) { - req->se->op.setlk(req, nodeid, &fi, &flock, sleep); - } else { - fuse_reply_err(req, ENOSYS); - } - } -} - -static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - do_setlk_common(req, nodeid, iter, 0); -} - -static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - do_setlk_common(req, nodeid, iter, 1); -} - -static int find_interrupted(struct fuse_session *se, struct fuse_req *req) -{ - struct fuse_req *curr; - - for (curr = se->list.next; curr != &se->list; curr = curr->next) { - if (curr->unique == req->u.i.unique) { - fuse_interrupt_func_t func; - void *data; - - curr->ctr++; - pthread_mutex_unlock(&se->lock); - - /* Ugh, ugly locking */ - pthread_mutex_lock(&curr->lock); - pthread_mutex_lock(&se->lock); - curr->interrupted = 1; - func = curr->u.ni.func; - data = curr->u.ni.data; - pthread_mutex_unlock(&se->lock); - if (func) { - func(curr, data); - } - pthread_mutex_unlock(&curr->lock); - - pthread_mutex_lock(&se->lock); - curr->ctr--; - if (!curr->ctr) { - destroy_req(curr); - } - - return 1; - } - } - for (curr = se->interrupts.next; curr != &se->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->u.i.unique) { - return 1; - } - } - return 0; -} - -static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_interrupt_in *arg; - struct fuse_session *se = req->se; - - (void)nodeid; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n", - (unsigned long long)arg->unique); - - req->u.i.unique = arg->unique; - - pthread_mutex_lock(&se->lock); - if (find_interrupted(se, req)) { - destroy_req(req); - } else { - list_add_req(req, &se->interrupts); - } - pthread_mutex_unlock(&se->lock); -} - -static struct fuse_req *check_interrupt(struct fuse_session *se, - struct fuse_req *req) -{ - struct fuse_req *curr; - - for (curr = se->interrupts.next; curr != &se->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->unique) { - req->interrupted = 1; - list_del_req(curr); - g_free(curr); - return NULL; - } - } - curr = se->interrupts.next; - if (curr != &se->interrupts) { - list_del_req(curr); - list_init_req(curr); - return curr; - } else { - return NULL; - } -} - -static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_bmap_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - if (req->se->op.bmap) { - req->se->op.bmap(req, nodeid, arg->blocksize, arg->block); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_ioctl_in *arg; - unsigned int flags; - void *in_buf = NULL; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - flags = arg->flags; - if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) { - fuse_reply_err(req, ENOTTY); - return; - } - - if (arg->in_size) { - in_buf = fuse_mbuf_iter_advance(iter, arg->in_size); - if (!in_buf) { - fuse_reply_err(req, EINVAL); - return; - } - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (sizeof(void *) == 4 && !(flags & FUSE_IOCTL_32BIT)) { - req->ioctl_64bit = 1; - } - - if (req->se->op.ioctl) { - req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg, - &fi, flags, in_buf, arg->in_size, arg->out_size); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -void fuse_pollhandle_destroy(struct fuse_pollhandle *ph) -{ - free(ph); -} - -static void do_poll(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_poll_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.poll_events = arg->events; - - if (req->se->op.poll) { - struct fuse_pollhandle *ph = NULL; - - if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) { - ph = malloc(sizeof(struct fuse_pollhandle)); - if (ph == NULL) { - fuse_reply_err(req, ENOMEM); - return; - } - ph->kh = arg->kh; - ph->se = req->se; - } - - req->se->op.poll(req, nodeid, &fi, ph); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_fallocate_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.fallocate) { - req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, - &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, - struct fuse_mbuf_iter *iter) -{ - struct fuse_copy_file_range_in *arg; - struct fuse_file_info fi_in, fi_out; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - memset(&fi_in, 0, sizeof(fi_in)); - fi_in.fh = arg->fh_in; - - memset(&fi_out, 0, sizeof(fi_out)); - fi_out.fh = arg->fh_out; - - - if (req->se->op.copy_file_range) { - req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in, - arg->nodeid_out, arg->off_out, &fi_out, - arg->len, arg->flags); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_lseek_in *arg; - struct fuse_file_info fi; - - arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->se->op.lseek) { - req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_syncfs(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - if (req->se->op.syncfs) { - req->se->op.syncfs(req, nodeid); - } else { - fuse_reply_err(req, ENOSYS); - } -} - -static void do_init(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - size_t compat_size = offsetof(struct fuse_init_in, max_readahead); - size_t compat2_size = offsetof(struct fuse_init_in, flags) + - sizeof(uint32_t); - /* Fuse structure extended with minor version 36 */ - size_t compat3_size = endof(struct fuse_init_in, unused); - struct fuse_init_in *arg; - struct fuse_init_out outarg; - struct fuse_session *se = req->se; - size_t bufsize = se->bufsize; - size_t outargsize = sizeof(outarg); - uint64_t flags = 0; - - (void)nodeid; - - /* First consume the old fields... */ - arg = fuse_mbuf_iter_advance(iter, compat_size); - if (!arg) { - fuse_reply_err(req, EINVAL); - return; - } - - /* ...and now consume the new fields. */ - if (arg->major == 7 && arg->minor >= 6) { - if (!fuse_mbuf_iter_advance(iter, compat2_size - compat_size)) { - fuse_reply_err(req, EINVAL); - return; - } - flags |= arg->flags; - } - - /* - * fuse_init_in was extended again with minor version 36. Just read - * current known size of fuse_init so that future extension and - * header rebase does not cause breakage. - */ - if (sizeof(*arg) > compat2_size && (arg->flags & FUSE_INIT_EXT)) { - if (!fuse_mbuf_iter_advance(iter, compat3_size - compat2_size)) { - fuse_reply_err(req, EINVAL); - return; - } - flags |= (uint64_t) arg->flags2 << 32; - } - - fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor); - if (arg->major == 7 && arg->minor >= 6) { - fuse_log(FUSE_LOG_DEBUG, "flags=0x%016" PRIx64 "\n", flags); - fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead); - } - se->conn.proto_major = arg->major; - se->conn.proto_minor = arg->minor; - se->conn.capable = 0; - se->conn.want = 0; - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - - if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) { - fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (arg->major > 7) { - /* Wait for a second INIT request with a 7.X version */ - send_reply_ok(req, &outarg, sizeof(outarg)); - return; - } - - if (arg->max_readahead < se->conn.max_readahead) { - se->conn.max_readahead = arg->max_readahead; - } - if (flags & FUSE_ASYNC_READ) { - se->conn.capable |= FUSE_CAP_ASYNC_READ; - } - if (flags & FUSE_POSIX_LOCKS) { - se->conn.capable |= FUSE_CAP_POSIX_LOCKS; - } - if (flags & FUSE_ATOMIC_O_TRUNC) { - se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; - } - if (flags & FUSE_EXPORT_SUPPORT) { - se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; - } - if (flags & FUSE_DONT_MASK) { - se->conn.capable |= FUSE_CAP_DONT_MASK; - } - if (flags & FUSE_FLOCK_LOCKS) { - se->conn.capable |= FUSE_CAP_FLOCK_LOCKS; - } - if (flags & FUSE_AUTO_INVAL_DATA) { - se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA; - } - if (flags & FUSE_DO_READDIRPLUS) { - se->conn.capable |= FUSE_CAP_READDIRPLUS; - } - if (flags & FUSE_READDIRPLUS_AUTO) { - se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO; - } - if (flags & FUSE_ASYNC_DIO) { - se->conn.capable |= FUSE_CAP_ASYNC_DIO; - } - if (flags & FUSE_WRITEBACK_CACHE) { - se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; - } - if (flags & FUSE_NO_OPEN_SUPPORT) { - se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT; - } - if (flags & FUSE_PARALLEL_DIROPS) { - se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; - } - if (flags & FUSE_POSIX_ACL) { - se->conn.capable |= FUSE_CAP_POSIX_ACL; - } - if (flags & FUSE_HANDLE_KILLPRIV) { - se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV; - } - if (flags & FUSE_NO_OPENDIR_SUPPORT) { - se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT; - } - if (!(flags & FUSE_MAX_PAGES)) { - size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() + - FUSE_BUFFER_HEADER_SIZE; - if (bufsize > max_bufsize) { - bufsize = max_bufsize; - } - } - if (flags & FUSE_SUBMOUNTS) { - se->conn.capable |= FUSE_CAP_SUBMOUNTS; - } - if (flags & FUSE_HANDLE_KILLPRIV_V2) { - se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2; - } - if (flags & FUSE_SETXATTR_EXT) { - se->conn.capable |= FUSE_CAP_SETXATTR_EXT; - } - if (flags & FUSE_SECURITY_CTX) { - se->conn.capable |= FUSE_CAP_SECURITY_CTX; - } -#ifdef HAVE_SPLICE -#ifdef HAVE_VMSPLICE - se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; -#endif - se->conn.capable |= FUSE_CAP_SPLICE_READ; -#endif - se->conn.capable |= FUSE_CAP_IOCTL_DIR; - - /* - * Default settings for modern filesystems. - * - * Most of these capabilities were disabled by default in - * libfuse2 for backwards compatibility reasons. In libfuse3, - * we can finally enable them by default (as long as they're - * supported by the kernel). - */ -#define LL_SET_DEFAULT(cond, cap) \ - if ((cond) && (se->conn.capable & (cap))) \ - se->conn.want |= (cap) - LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ); - LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS); - LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA); - LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV); - LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO); - LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR); - LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC); - LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ); - LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS); - LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS); - LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS); - LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir, - FUSE_CAP_READDIRPLUS_AUTO); - se->conn.time_gran = 1; - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - se->bufsize = bufsize; - - if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE) { - se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE; - } - - se->got_init = 1; - se->got_destroy = 0; - if (se->op.init) { - se->op.init(se->userdata, &se->conn); - } - - if (se->conn.want & (~se->conn.capable)) { - fuse_log(FUSE_LOG_ERR, - "fuse: error: filesystem requested capabilities " - "0x%" PRIx64 " that are not supported by kernel, aborting.\n", - se->conn.want & (~se->conn.capable)); - fuse_reply_err(req, EPROTO); - se->error = -EPROTO; - fuse_session_exit(se); - return; - } - - if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) { - se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE; - } - if (flags & FUSE_MAX_PAGES) { - outarg.flags |= FUSE_MAX_PAGES; - outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1; - } - - /* - * Always enable big writes, this is superseded - * by the max_write option - */ - outarg.flags |= FUSE_BIG_WRITES; - - if (se->conn.want & FUSE_CAP_ASYNC_READ) { - outarg.flags |= FUSE_ASYNC_READ; - } - if (se->conn.want & FUSE_CAP_PARALLEL_DIROPS) { - outarg.flags |= FUSE_PARALLEL_DIROPS; - } - if (se->conn.want & FUSE_CAP_POSIX_LOCKS) { - outarg.flags |= FUSE_POSIX_LOCKS; - } - if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) { - outarg.flags |= FUSE_ATOMIC_O_TRUNC; - } - if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT) { - outarg.flags |= FUSE_EXPORT_SUPPORT; - } - if (se->conn.want & FUSE_CAP_DONT_MASK) { - outarg.flags |= FUSE_DONT_MASK; - } - if (se->conn.want & FUSE_CAP_FLOCK_LOCKS) { - outarg.flags |= FUSE_FLOCK_LOCKS; - } - if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA) { - outarg.flags |= FUSE_AUTO_INVAL_DATA; - } - if (se->conn.want & FUSE_CAP_READDIRPLUS) { - outarg.flags |= FUSE_DO_READDIRPLUS; - } - if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO) { - outarg.flags |= FUSE_READDIRPLUS_AUTO; - } - if (se->conn.want & FUSE_CAP_ASYNC_DIO) { - outarg.flags |= FUSE_ASYNC_DIO; - } - if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE) { - outarg.flags |= FUSE_WRITEBACK_CACHE; - } - if (se->conn.want & FUSE_CAP_POSIX_ACL) { - outarg.flags |= FUSE_POSIX_ACL; - } - outarg.max_readahead = se->conn.max_readahead; - outarg.max_write = se->conn.max_write; - if (se->conn.max_background >= (1 << 16)) { - se->conn.max_background = (1 << 16) - 1; - } - if (se->conn.congestion_threshold > se->conn.max_background) { - se->conn.congestion_threshold = se->conn.max_background; - } - if (!se->conn.congestion_threshold) { - se->conn.congestion_threshold = se->conn.max_background * 3 / 4; - } - - outarg.max_background = se->conn.max_background; - outarg.congestion_threshold = se->conn.congestion_threshold; - outarg.time_gran = se->conn.time_gran; - - if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV_V2) { - outarg.flags |= FUSE_HANDLE_KILLPRIV_V2; - } - - if (se->conn.want & FUSE_CAP_SETXATTR_EXT) { - outarg.flags |= FUSE_SETXATTR_EXT; - } - - if (se->conn.want & FUSE_CAP_SECURITY_CTX) { - /* bits 32..63 get shifted down 32 bits into the flags2 field */ - outarg.flags2 |= FUSE_SECURITY_CTX >> 32; - } - - fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor); - fuse_log(FUSE_LOG_DEBUG, " flags2=0x%08x flags=0x%08x\n", outarg.flags2, - outarg.flags); - fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n", outarg.max_readahead); - fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write); - fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n", outarg.max_background); - fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n", - outarg.congestion_threshold); - fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n", outarg.time_gran); - - send_reply_ok(req, &outarg, outargsize); -} - -static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, - struct fuse_mbuf_iter *iter) -{ - struct fuse_session *se = req->se; - - (void)nodeid; - (void)iter; - - se->got_destroy = 1; - se->got_init = 0; - if (se->op.destroy) { - se->op.destroy(se->userdata); - } - - send_reply_ok(req, NULL, 0); -} - -int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv) -{ - struct fuse_out_header out = { - .error = FUSE_NOTIFY_STORE, - }; - struct fuse_notify_store_out outarg = { - .nodeid = ino, - .offset = offset, - .size = fuse_buf_size(bufv), - }; - struct iovec iov[3]; - int res; - - if (!se) { - return -EINVAL; - } - - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(out); - iov[1].iov_base = &outarg; - iov[1].iov_len = sizeof(outarg); - - res = fuse_send_data_iov(se, NULL, iov, 2, bufv); - if (res > 0) { - res = -res; - } - - return res; -} - -void *fuse_req_userdata(fuse_req_t req) -{ - return req->se->userdata; -} - -const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) -{ - return &req->ctx; -} - -void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data) -{ - pthread_mutex_lock(&req->lock); - pthread_mutex_lock(&req->se->lock); - req->u.ni.func = func; - req->u.ni.data = data; - pthread_mutex_unlock(&req->se->lock); - if (req->interrupted && func) { - func(req, data); - } - pthread_mutex_unlock(&req->lock); -} - -int fuse_req_interrupted(fuse_req_t req) -{ - int interrupted; - - pthread_mutex_lock(&req->se->lock); - interrupted = req->interrupted; - pthread_mutex_unlock(&req->se->lock); - - return interrupted; -} - -static struct { - void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *); - const char *name; -} fuse_ll_ops[] = { - [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, - [FUSE_FORGET] = { do_forget, "FORGET" }, - [FUSE_GETATTR] = { do_getattr, "GETATTR" }, - [FUSE_SETATTR] = { do_setattr, "SETATTR" }, - [FUSE_READLINK] = { do_readlink, "READLINK" }, - [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, - [FUSE_MKNOD] = { do_mknod, "MKNOD" }, - [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, - [FUSE_UNLINK] = { do_unlink, "UNLINK" }, - [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, - [FUSE_RENAME] = { do_rename, "RENAME" }, - [FUSE_LINK] = { do_link, "LINK" }, - [FUSE_OPEN] = { do_open, "OPEN" }, - [FUSE_READ] = { do_read, "READ" }, - [FUSE_WRITE] = { do_write, "WRITE" }, - [FUSE_STATFS] = { do_statfs, "STATFS" }, - [FUSE_RELEASE] = { do_release, "RELEASE" }, - [FUSE_FSYNC] = { do_fsync, "FSYNC" }, - [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, - [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, - [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, - [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, - [FUSE_FLUSH] = { do_flush, "FLUSH" }, - [FUSE_INIT] = { do_init, "INIT" }, - [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, - [FUSE_READDIR] = { do_readdir, "READDIR" }, - [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, - [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, - [FUSE_GETLK] = { do_getlk, "GETLK" }, - [FUSE_SETLK] = { do_setlk, "SETLK" }, - [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, - [FUSE_ACCESS] = { do_access, "ACCESS" }, - [FUSE_CREATE] = { do_create, "CREATE" }, - [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, - [FUSE_BMAP] = { do_bmap, "BMAP" }, - [FUSE_IOCTL] = { do_ioctl, "IOCTL" }, - [FUSE_POLL] = { do_poll, "POLL" }, - [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" }, - [FUSE_DESTROY] = { do_destroy, "DESTROY" }, - [FUSE_NOTIFY_REPLY] = { NULL, "NOTIFY_REPLY" }, - [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, - [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" }, - [FUSE_RENAME2] = { do_rename2, "RENAME2" }, - [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, - [FUSE_LSEEK] = { do_lseek, "LSEEK" }, - [FUSE_SYNCFS] = { do_syncfs, "SYNCFS" }, -}; - -#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) - -static const char *opname(enum fuse_opcode opcode) -{ - if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) { - return "???"; - } else { - return fuse_ll_ops[opcode].name; - } -} - -void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf) -{ - struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; - fuse_session_process_buf_int(se, &bufv, NULL); -} - -/* - * Restriction: - * bufv is normally a single entry buffer, except for a write - * where (if it's in memory) then the bufv may be multiple entries, - * where the first entry contains all headers and subsequent entries - * contain data - * bufv shall not use any offsets etc to make the data anything - * other than contiguous starting from 0. - */ -void fuse_session_process_buf_int(struct fuse_session *se, - struct fuse_bufvec *bufv, - struct fuse_chan *ch) -{ - const struct fuse_buf *buf = bufv->buf; - struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf); - struct fuse_in_header *in; - struct fuse_req *req; - int err; - - /* The first buffer must be a memory buffer */ - assert(!(buf->flags & FUSE_BUF_IS_FD)); - - in = fuse_mbuf_iter_advance(&iter, sizeof(*in)); - assert(in); /* caller guarantees the input buffer is large enough */ - - fuse_log( - FUSE_LOG_DEBUG, - "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n", - (unsigned long long)in->unique, opname((enum fuse_opcode)in->opcode), - in->opcode, (unsigned long long)in->nodeid, buf->size, in->pid); - - req = fuse_ll_alloc_req(se); - if (req == NULL) { - struct fuse_out_header out = { - .unique = in->unique, - .error = -ENOMEM, - }; - struct iovec iov = { - .iov_base = &out, - .iov_len = sizeof(struct fuse_out_header), - }; - - fuse_send_msg(se, ch, &iov, 1); - return; - } - - req->unique = in->unique; - req->ctx.uid = in->uid; - req->ctx.gid = in->gid; - req->ctx.pid = in->pid; - req->ch = ch; - - /* - * INIT and DESTROY requests are serialized, all other request types - * run in parallel. This prevents races between FUSE_INIT and ordinary - * requests, FUSE_INIT and FUSE_INIT, FUSE_INIT and FUSE_DESTROY, and - * FUSE_DESTROY and FUSE_DESTROY. - */ - if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT || - in->opcode == FUSE_DESTROY) { - pthread_rwlock_wrlock(&se->init_rwlock); - } else { - pthread_rwlock_rdlock(&se->init_rwlock); - } - - err = EIO; - if (!se->got_init) { - enum fuse_opcode expected; - - expected = se->cuse_data ? CUSE_INIT : FUSE_INIT; - if (in->opcode != expected) { - goto reply_err; - } - } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) { - if (fuse_lowlevel_is_virtio(se)) { - /* - * TODO: This is after a hard reboot typically, we need to do - * a destroy, but we can't reply to this request yet so - * we can't use do_destroy - */ - fuse_log(FUSE_LOG_DEBUG, "%s: reinit\n", __func__); - se->got_destroy = 1; - se->got_init = 0; - if (se->op.destroy) { - se->op.destroy(se->userdata); - } - } else { - goto reply_err; - } - } - - err = EACCES; - /* Implement -o allow_root */ - if (se->deny_others && in->uid != se->owner && in->uid != 0 && - in->opcode != FUSE_INIT && in->opcode != FUSE_READ && - in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && - in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && - in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR && - in->opcode != FUSE_NOTIFY_REPLY && in->opcode != FUSE_READDIRPLUS) { - goto reply_err; - } - - err = ENOSYS; - if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) { - goto reply_err; - } - if (in->opcode != FUSE_INTERRUPT) { - struct fuse_req *intr; - pthread_mutex_lock(&se->lock); - intr = check_interrupt(se, req); - list_add_req(req, &se->list); - pthread_mutex_unlock(&se->lock); - if (intr) { - fuse_reply_err(intr, EAGAIN); - } - } - - if (in->opcode == FUSE_WRITE && se->op.write_buf) { - do_write_buf(req, in->nodeid, &iter, bufv); - } else { - fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter); - } - - pthread_rwlock_unlock(&se->init_rwlock); - return; - -reply_err: - fuse_reply_err(req, err); - pthread_rwlock_unlock(&se->init_rwlock); -} - -#define LL_OPTION(n, o, v) \ - { \ - n, offsetof(struct fuse_session, o), v \ - } - -static const struct fuse_opt fuse_ll_opts[] = { - LL_OPTION("debug", debug, 1), - LL_OPTION("-d", debug, 1), - LL_OPTION("--debug", debug, 1), - LL_OPTION("allow_root", deny_others, 1), - LL_OPTION("--socket-path=%s", vu_socket_path, 0), - LL_OPTION("--socket-group=%s", vu_socket_group, 0), - LL_OPTION("--fd=%d", vu_listen_fd, 0), - LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0), - FUSE_OPT_END -}; - -void fuse_lowlevel_version(void) -{ - printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION, - FUSE_KERNEL_MINOR_VERSION); -} - -void fuse_lowlevel_help(void) -{ - /* - * These are not all options, but the ones that are - * potentially of interest to an end-user - */ - printf( - " -o allow_root allow access by root\n" - " --socket-path=PATH path for the vhost-user socket\n" - " --socket-group=GRNAME name of group for the vhost-user socket\n" - " --fd=FDNUM fd number of vhost-user socket\n" - " --thread-pool-size=NUM thread pool size limit (default %d)\n", - THREAD_POOL_SIZE); -} - -void fuse_session_destroy(struct fuse_session *se) -{ - if (se->got_init && !se->got_destroy) { - if (se->op.destroy) { - se->op.destroy(se->userdata); - } - } - pthread_rwlock_destroy(&se->init_rwlock); - pthread_mutex_destroy(&se->lock); - free(se->cuse_data); - if (se->fd != -1) { - close(se->fd); - } - - if (fuse_lowlevel_is_virtio(se)) { - virtio_session_close(se); - } - - free(se->vu_socket_path); - se->vu_socket_path = NULL; - - g_free(se); -} - - -struct fuse_session *fuse_session_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) -{ - struct fuse_session *se; - - if (sizeof(struct fuse_lowlevel_ops) < op_size) { - fuse_log( - FUSE_LOG_ERR, - "fuse: warning: library too old, some operations may not work\n"); - op_size = sizeof(struct fuse_lowlevel_ops); - } - - if (args->argc == 0) { - fuse_log(FUSE_LOG_ERR, - "fuse: empty argv passed to fuse_session_new().\n"); - return NULL; - } - - se = g_try_new0(struct fuse_session, 1); - if (se == NULL) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n"); - goto out1; - } - se->fd = -1; - se->vu_listen_fd = -1; - se->thread_pool_size = THREAD_POOL_SIZE; - se->conn.max_write = UINT_MAX; - se->conn.max_readahead = UINT_MAX; - - /* Parse options */ - if (fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) { - goto out2; - } - if (args->argc == 1 && args->argv[0][0] == '-') { - fuse_log(FUSE_LOG_ERR, - "fuse: warning: argv[0] looks like an option, but " - "will be ignored\n"); - } else if (args->argc != 1) { - int i; - fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `"); - for (i = 1; i < args->argc - 1; i++) { - fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]); - } - fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]); - goto out4; - } - - if (!se->vu_socket_path && se->vu_listen_fd < 0) { - fuse_log(FUSE_LOG_ERR, "fuse: missing --socket-path or --fd option\n"); - goto out4; - } - if (se->vu_socket_path && se->vu_listen_fd >= 0) { - fuse_log(FUSE_LOG_ERR, - "fuse: --socket-path and --fd cannot be given together\n"); - goto out4; - } - if (se->vu_socket_group && !se->vu_socket_path) { - fuse_log(FUSE_LOG_ERR, - "fuse: --socket-group can only be used with --socket-path\n"); - goto out4; - } - - se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE; - - list_init_req(&se->list); - list_init_req(&se->interrupts); - fuse_mutex_init(&se->lock); - pthread_rwlock_init(&se->init_rwlock, NULL); - - memcpy(&se->op, op, op_size); - se->owner = getuid(); - se->userdata = userdata; - - return se; - -out4: - fuse_opt_free_args(args); -out2: - g_free(se); -out1: - return NULL; -} - -int fuse_session_mount(struct fuse_session *se) -{ - return virtio_session_mount(se); -} - -int fuse_session_fd(struct fuse_session *se) -{ - return se->fd; -} - -void fuse_session_unmount(struct fuse_session *se) -{ -} - -int fuse_lowlevel_is_virtio(struct fuse_session *se) -{ - return !!se->virtio_dev; -} - -void fuse_session_exit(struct fuse_session *se) -{ - se->exited = 1; -} - -void fuse_session_reset(struct fuse_session *se) -{ - se->exited = 0; - se->error = 0; -} - -int fuse_session_exited(struct fuse_session *se) -{ - return se->exited; -} diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h deleted file mode 100644 index b889dae4de..0000000000 --- a/tools/virtiofsd/fuse_lowlevel.h +++ /dev/null @@ -1,1988 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB. - */ - -#ifndef FUSE_LOWLEVEL_H_ -#define FUSE_LOWLEVEL_H_ - -/** - * @file - * - * Low level API - * - * IMPORTANT: you should define FUSE_USE_VERSION before including this - * header. To use the newest API define it to 31 (recommended for any - * new application). - */ - -#ifndef FUSE_USE_VERSION -#error FUSE_USE_VERSION not defined -#endif - -#include "fuse_common.h" - -#include -#include -#include - -/* - * Miscellaneous definitions - */ - -/** The node ID of the root inode */ -#define FUSE_ROOT_ID 1 - -/** Inode number type */ -typedef uint64_t fuse_ino_t; - -/** Request pointer type */ -typedef struct fuse_req *fuse_req_t; - -/** - * Session - * - * This provides hooks for processing requests, and exiting - */ -struct fuse_session; - -/** Directory entry parameters supplied to fuse_reply_entry() */ -struct fuse_entry_param { - /** - * Unique inode number - * - * In lookup, zero means negative entry (from version 2.5) - * Returning ENOENT also means negative entry, but by setting zero - * ino the kernel may cache negative entries for entry_timeout - * seconds. - */ - fuse_ino_t ino; - - /** - * Generation number for this entry. - * - * If the file system will be exported over NFS, the - * ino/generation pairs need to be unique over the file - * system's lifetime (rather than just the mount time). So if - * the file system reuses an inode after it has been deleted, - * it must assign a new, previously unused generation number - * to the inode at the same time. - * - */ - uint64_t generation; - - /** - * Inode attributes. - * - * Even if attr_timeout == 0, attr must be correct. For example, - * for open(), FUSE uses attr.st_size from lookup() to determine - * how many bytes to request. If this value is not correct, - * incorrect data will be returned. - */ - struct stat attr; - - /** - * Validity timeout (in seconds) for inode attributes. If - * attributes only change as a result of requests that come - * through the kernel, this should be set to a very large - * value. - */ - double attr_timeout; - - /** - * Validity timeout (in seconds) for the name. If directory - * entries are changed/deleted only as a result of requests - * that come through the kernel, this should be set to a very - * large value. - */ - double entry_timeout; - - /** - * Flags for fuse_attr.flags that do not fit into attr. - */ - uint32_t attr_flags; -}; - -/** - * Additional context associated with requests. - * - * Note that the reported client uid, gid and pid may be zero in some - * situations. For example, if the FUSE file system is running in a - * PID or user namespace but then accessed from outside the namespace, - * there is no valid uid/pid/gid that could be reported. - */ -struct fuse_ctx { - /** User ID of the calling process */ - uid_t uid; - - /** Group ID of the calling process */ - gid_t gid; - - /** Thread ID of the calling process */ - pid_t pid; - - /** Umask of the calling process */ - mode_t umask; -}; - -struct fuse_forget_data { - fuse_ino_t ino; - uint64_t nlookup; -}; - -/* 'to_set' flags in setattr */ -#define FUSE_SET_ATTR_MODE (1 << 0) -#define FUSE_SET_ATTR_UID (1 << 1) -#define FUSE_SET_ATTR_GID (1 << 2) -#define FUSE_SET_ATTR_SIZE (1 << 3) -#define FUSE_SET_ATTR_ATIME (1 << 4) -#define FUSE_SET_ATTR_MTIME (1 << 5) -#define FUSE_SET_ATTR_ATIME_NOW (1 << 7) -#define FUSE_SET_ATTR_MTIME_NOW (1 << 8) -#define FUSE_SET_ATTR_CTIME (1 << 10) -#define FUSE_SET_ATTR_KILL_SUIDGID (1 << 11) - -/* - * Request methods and replies - */ - -/** - * Low level filesystem operations - * - * Most of the methods (with the exception of init and destroy) - * receive a request handle (fuse_req_t) as their first argument. - * This handle must be passed to one of the specified reply functions. - * - * This may be done inside the method invocation, or after the call - * has returned. The request handle is valid until one of the reply - * functions is called. - * - * Other pointer arguments (name, fuse_file_info, etc) are not valid - * after the call has returned, so if they are needed later, their - * contents have to be copied. - * - * In general, all methods are expected to perform any necessary - * permission checking. However, a filesystem may delegate this task - * to the kernel by passing the `default_permissions` mount option to - * `fuse_session_new()`. In this case, methods will only be called if - * the kernel's permission check has succeeded. - * - * The filesystem sometimes needs to handle a return value of -ENOENT - * from the reply function, which means, that the request was - * interrupted, and the reply discarded. For example if - * fuse_reply_open() return -ENOENT means, that the release method for - * this file will not be called. - */ -struct fuse_lowlevel_ops { - /** - * Initialize filesystem - * - * This function is called when libfuse establishes - * communication with the FUSE kernel module. The file system - * should use this module to inspect and/or modify the - * connection parameters provided in the `conn` structure. - * - * Note that some parameters may be overwritten by options - * passed to fuse_session_new() which take precedence over the - * values set in this handler. - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_session_new() - */ - void (*init)(void *userdata, struct fuse_conn_info *conn); - - /** - * Clean up filesystem. - * - * Called on filesystem exit. When this method is called, the - * connection to the kernel may be gone already, so that eg. calls - * to fuse_lowlevel_notify_* will fail. - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_session_new() - */ - void (*destroy)(void *userdata); - - /** - * Look up a directory entry by name and get its attributes. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name the name to look up - */ - void (*lookup)(fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Forget about an inode - * - * This function is called when the kernel removes an inode - * from its internal caches. - * - * The inode's lookup count increases by one for every call to - * fuse_reply_entry and fuse_reply_create. The nlookup parameter - * indicates by how much the lookup count should be decreased. - * - * Inodes with a non-zero lookup count may receive request from - * the kernel even after calls to unlink, rmdir or (when - * overwriting an existing file) rename. Filesystems must handle - * such requests properly and it is recommended to defer removal - * of the inode until the lookup count reaches zero. Calls to - * unlink, rmdir or rename will be followed closely by forget - * unless the file or directory is open, in which case the - * kernel issues forget only after the release or releasedir - * calls. - * - * Note that if a file system will be exported over NFS the - * inodes lifetime must extend even beyond forget. See the - * generation field in struct fuse_entry_param above. - * - * On unmount the lookup count for all inodes implicitly drops - * to zero. It is not guaranteed that the file system will - * receive corresponding forget messages for the affected - * inodes. - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - * @param ino the inode number - * @param nlookup the number of lookups to forget - */ - void (*forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); - - /** - * Get file attributes. - * - * If writeback caching is enabled, the kernel may have a - * better idea of a file's length than the FUSE file system - * (eg if there has been a write that extended the file size, - * but that has not yet been passed to the filesystem.n - * - * In this case, the st_size value provided by the file system - * will be ignored. - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi for future use, currently always NULL - */ - void (*getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Set file attributes - * - * In the 'attr' argument only members indicated by the 'to_set' - * bitmask contain valid values. Other members contain undefined - * values. - * - * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is - * expected to reset the setuid and setgid bits if the file - * size or owner is being changed. - * - * If the setattr was invoked from the ftruncate() system call - * under Linux kernel versions 2.6.15 or later, the fi->fh will - * contain the value set by the open method or will be undefined - * if the open method didn't set any value. Otherwise (not - * ftruncate call, or kernel version earlier than 2.6.15) the fi - * parameter will be NULL. - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param attr the attributes - * @param to_set bit mask of attributes which should be set - * @param fi file information, or NULL - */ - void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - - /** - * Read symbolic link - * - * Valid replies: - * fuse_reply_readlink - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - */ - void (*readlink)(fuse_req_t req, fuse_ino_t ino); - - /** - * Create file node - * - * Create a regular file, character device, block device, fifo or - * socket node. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param rdev the device number (only valid if created file is a device) - */ - void (*mknod)(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - - /** - * Create a directory - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode with which to create the new file - */ - void (*mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - - /** - * Remove a file - * - * If the file's inode's lookup count is non-zero, the file - * system is expected to postpone any removal of the inode - * until the lookup count reaches zero (see description of the - * forget function). - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*unlink)(fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Remove a directory - * - * If the directory's inode's lookup count is non-zero, the - * file system is expected to postpone any removal of the - * inode until the lookup count reaches zero (see description - * of the forget function). - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Create a symbolic link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param link the contents of the symbolic link - * @param parent inode number of the parent directory - * @param name to create - */ - void (*symlink)(fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - - /** - * Rename a file - * - * If the target exists it should be atomically replaced. If - * the target's inode's lookup count is non-zero, the file - * system is expected to postpone any removal of the inode - * until the lookup count reaches zero (see description of the - * forget function). - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EINVAL, i.e. all - * future bmap requests will fail with EINVAL without being - * send to the filesystem process. - * - * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If - * RENAME_NOREPLACE is specified, the filesystem must not - * overwrite *newname* if it exists and return an error - * instead. If `RENAME_EXCHANGE` is specified, the filesystem - * must atomically exchange the two files, i.e. both must - * exist and neither may be deleted. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the old parent directory - * @param name old name - * @param newparent inode number of the new parent directory - * @param newname new name - */ - void (*rename)(fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname, - unsigned int flags); - - /** - * Create a hard link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param ino the old inode number - * @param newparent inode number of the new parent directory - * @param newname new name to create - */ - void (*link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - - /** - * Open a file - * - * Open flags are available in fi->flags. The following rules - * apply. - * - * - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be - * filtered out / handled by the kernel. - * - * - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used - * by the filesystem to check if the operation is - * permitted. If the ``-o default_permissions`` mount - * option is given, this check is already done by the - * kernel before calling open() and may thus be omitted by - * the filesystem. - * - * - When writeback caching is enabled, the kernel may send - * read requests even for files opened with O_WRONLY. The - * filesystem should be prepared to handle this. - * - * - When writeback caching is disabled, the filesystem is - * expected to properly handle the O_APPEND flag and ensure - * that each write is appending to the end of the file. - * - * - When writeback caching is enabled, the kernel will - * handle O_APPEND. However, unless all changes to the file - * come through the kernel this will not work reliably. The - * filesystem should thus either ignore the O_APPEND flag - * (and let the kernel handle it), or return an error - * (indicating that reliably O_APPEND is not available). - * - * Filesystem may store an arbitrary file handle (pointer, - * index, etc) in fi->fh, and use this in other all other file - * operations (read, write, flush, release, fsync). - * - * Filesystem may also implement stateless file I/O and not store - * anything in fi->fh. - * - * There are also some flags (direct_io, keep_cache) which the - * filesystem may set in fi, to change the way the file is opened. - * See fuse_file_info structure in for more details. - * - * If this request is answered with an error code of ENOSYS - * and FUSE_CAP_NO_OPEN_SUPPORT is set in - * `fuse_conn_info.capable`, this is treated as success and - * future calls to open and release will also succeed without being - * sent to the filesystem process. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Read data - * - * Read should send exactly the number of bytes requested except - * on EOF or error, otherwise the rest of the data will be - * substituted with zeroes. An exception to this is when the file - * has been opened in 'direct_io' mode, in which case the return - * value of the read system call will reflect the return value of - * this operation. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_iov - * fuse_reply_data - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size number of bytes to read - * @param off offset to read from - * @param fi file information - */ - void (*read)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Write data - * - * Write should return exactly the number of bytes requested - * except on error. An exception to this is when the file has - * been opened in 'direct_io' mode, in which case the return value - * of the write system call will reflect the return value of this - * operation. - * - * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is - * expected to reset the setuid and setgid bits. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param buf data to write - * @param size number of bytes to write - * @param off offset to write to - * @param fi file information - */ - void (*write)(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, - off_t off, struct fuse_file_info *fi); - - /** - * Flush method - * - * This is called on each close() of the opened file. - * - * Since file descriptors can be duplicated (dup, dup2, fork), for - * one open call there may be many flush calls. - * - * Filesystems shouldn't assume that flush will always be called - * after some writes, or that if will be called at all. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * NOTE: the name of the method is misleading, since (unlike - * fsync) the filesystem is not forced to flush pending writes. - * One reason to flush data is if the filesystem wants to return - * write errors during close. However, such use is non-portable - * because POSIX does not require [close] to wait for delayed I/O to - * complete. - * - * If the filesystem supports file locking operations (setlk, - * getlk) it should remove all locks belonging to 'fi->owner'. - * - * If this request is answered with an error code of ENOSYS, - * this is treated as success and future calls to flush() will - * succeed automatically without being send to the filesystem - * process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * - * [close]: - * http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html - */ - void (*flush)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Release an open file - * - * Release is called when there are no more references to an open - * file: all file descriptors are closed and all memory mappings - * are unmapped. - * - * For every open call there will be exactly one release call (unless - * the filesystem is force-unmounted). - * - * The filesystem may reply with an error, but error values are - * not returned to close() or munmap() which triggered the - * release. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * fi->flags will contain the same flags as for open. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Synchronize file contents - * - * If the datasync parameter is non-zero, then only the user data - * should be flushed, not the meta data. - * - * If this request is answered with an error code of ENOSYS, - * this is treated as success and future calls to fsync() will - * succeed automatically without being send to the filesystem - * process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsync)(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Open a directory - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other directory - * stream operations (readdir, releasedir, fsyncdir). - * - * If this request is answered with an error code of ENOSYS and - * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`, - * this is treated as success and future calls to opendir and - * releasedir will also succeed without being sent to the filesystem - * process. In addition, the kernel will cache readdir results - * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Read directory - * - * Send a buffer filled using fuse_add_direntry(), with size not - * exceeding the requested size. Send an empty buffer on end of - * stream. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Returning a directory entry from readdir() does not affect - * its lookup count. - * - * If off_t is non-zero, then it will correspond to one of the off_t - * values that was previously returned by readdir() for the same - * directory handle. In this case, readdir() should skip over entries - * coming before the position defined by the off_t value. If entries - * are added or removed while the directory handle is open, they filesystem - * may still include the entries that have been removed, and may not - * report the entries that have been created. However, addition or - * removal of entries must never cause readdir() to skip over unrelated - * entries or to report them more than once. This means - * that off_t can not be a simple index that enumerates the entries - * that have been returned but must contain sufficient information to - * uniquely determine the next directory entry to return even when the - * set of entries is changing. - * - * The function does not have to report the '.' and '..' - * entries, but is allowed to do so. Note that, if readdir does - * not return '.' or '..', they will not be implicitly returned, - * and this behavior is observable by the caller. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum number of bytes to send - * @param off offset to continue reading the directory stream - * @param fi file information - */ - void (*readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Release an open directory - * - * For every opendir call there will be exactly one releasedir - * call (unless the filesystem is force-unmounted). - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*releasedir)(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Synchronize directory contents - * - * If the datasync parameter is non-zero, then only the directory - * contents should be flushed, not the meta data. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * If this request is answered with an error code of ENOSYS, - * this is treated as success and future calls to fsyncdir() will - * succeed automatically without being send to the filesystem - * process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Get file system statistics - * - * Valid replies: - * fuse_reply_statfs - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number, zero means "undefined" - */ - void (*statfs)(fuse_req_t req, fuse_ino_t ino); - - /** - * Set an extended attribute - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future setxattr() requests will fail with EOPNOTSUPP without being - * send to the filesystem process. - * - * Valid replies: - * fuse_reply_err - */ - void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags, - uint32_t setxattr_flags); - - /** - * Get an extended attribute - * - * If size is zero, the size of the value should be sent with - * fuse_reply_xattr. - * - * If the size is non-zero, and the value fits in the buffer, the - * value should be sent with fuse_reply_buf. - * - * If the size is too small for the value, the ERANGE error should - * be sent. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future getxattr() requests will fail with EOPNOTSUPP without being - * send to the filesystem process. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - * @param size maximum size of the value to send - */ - void (*getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - - /** - * List extended attribute names - * - * If size is zero, the total size of the attribute list should be - * sent with fuse_reply_xattr. - * - * If the size is non-zero, and the null character separated - * attribute list fits in the buffer, the list should be sent with - * fuse_reply_buf. - * - * If the size is too small for the list, the ERANGE error should - * be sent. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future listxattr() requests will fail with EOPNOTSUPP without being - * send to the filesystem process. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum size of the list to send - */ - void (*listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size); - - /** - * Remove an extended attribute - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future removexattr() requests will fail with EOPNOTSUPP without being - * send to the filesystem process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - */ - void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name); - - /** - * Check file access permissions - * - * This will be called for the access() and chdir() system - * calls. If the 'default_permissions' mount option is given, - * this method is not called. - * - * This method is not called under Linux kernel versions 2.4.x - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent success, i.e. this and all future access() - * requests will succeed without being send to the filesystem process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param mask requested access mode - */ - void (*access)(fuse_req_t req, fuse_ino_t ino, int mask); - - /** - * Create and open a file - * - * If the file does not exist, first create it with the specified - * mode, and then open it. - * - * See the description of the open handler for more - * information. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the mknod() and open() methods - * will be called instead. - * - * If this request is answered with an error code of ENOSYS, the handler - * is treated as not implemented (i.e., for this and future requests the - * mknod() and open() handlers will be called instead). - * - * Valid replies: - * fuse_reply_create - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param fi file information - */ - void (*create)(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); - - /** - * Test for a POSIX file lock - * - * Valid replies: - * fuse_reply_lock - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to test - */ - void (*getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock); - - /** - * Acquire, modify or release a POSIX file lock - * - * For POSIX threads (NPTL) there's a 1-1 relation between pid and - * owner, but otherwise this is not always the case. For checking - * lock ownership, 'fi->owner' must be used. The l_pid field in - * 'struct flock' should only be used to fill in this field in - * getlk(). - * - * Note: if the locking methods are not implemented, the kernel - * will still allow file locking to work locally. Hence these are - * only interesting for network filesystems and similar. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to set - * @param sleep locking operation may sleep - */ - void (*setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock, int sleep); - - /** - * Map block index within file to block index within device - * - * Note: This makes sense only for block device backed filesystems - * mounted with the 'blkdev' option - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure, i.e. all future bmap() requests will - * fail with the same error code without being send to the filesystem - * process. - * - * Valid replies: - * fuse_reply_bmap - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param blocksize unit of block index - * @param idx block index within file - */ - void (*bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize, - uint64_t idx); - - /** - * Ioctl - * - * Note: For unrestricted ioctls (not allowed for FUSE - * servers), data in and out areas can be discovered by giving - * iovs and setting FUSE_IOCTL_RETRY in *flags*. For - * restricted ioctls, kernel prepares in/out data area - * according to the information encoded in cmd. - * - * Valid replies: - * fuse_reply_ioctl_retry - * fuse_reply_ioctl - * fuse_reply_ioctl_iov - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param cmd ioctl command - * @param arg ioctl argument - * @param fi file information - * @param flags for FUSE_IOCTL_* flags - * @param in_buf data fetched from the caller - * @param in_bufsz number of fetched bytes - * @param out_bufsz maximum size of output data - * - * Note : the unsigned long request submitted by the application - * is truncated to 32 bits. - */ - void (*ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, - struct fuse_file_info *fi, unsigned flags, const void *in_buf, - size_t in_bufsz, size_t out_bufsz); - - /** - * Poll for IO readiness - * - * Note: If ph is non-NULL, the client should notify - * when IO readiness events occur by calling - * fuse_lowlevel_notify_poll() with the specified ph. - * - * Regardless of the number of times poll with a non-NULL ph - * is received, single notification is enough to clear all. - * Notifying more times incurs overhead but doesn't harm - * correctness. - * - * The callee is responsible for destroying ph with - * fuse_pollhandle_destroy() when no longer in use. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as success (with a kernel-defined default poll-mask) and - * future calls to pull() will succeed the same way without being send - * to the filesystem process. - * - * Valid replies: - * fuse_reply_poll - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param ph poll handle to be used for notification - */ - void (*poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct fuse_pollhandle *ph); - - /** - * Write data made available in a buffer - * - * This is a more generic version of the ->write() method. If - * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the - * kernel supports splicing from the fuse device, then the - * data will be made available in pipe for supporting zero - * copy data transfer. - * - * buf->count is guaranteed to be one (and thus buf->idx is - * always zero). The write_buf handler must ensure that - * bufv->off is correctly updated (reflecting the number of - * bytes read from bufv->buf[0]). - * - * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is - * expected to reset the setuid and setgid bits. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param bufv buffer containing the data - * @param off offset to write to - * @param fi file information - */ - void (*write_buf)(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, - off_t off, struct fuse_file_info *fi); - - /** - * Forget about multiple inodes - * - * See description of the forget function for more - * information. - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - */ - void (*forget_multi)(fuse_req_t req, size_t count, - struct fuse_forget_data *forgets); - - /** - * Acquire, modify or release a BSD file lock - * - * Note: if the locking methods are not implemented, the kernel - * will still allow file locking to work locally. Hence these are - * only interesting for network filesystems and similar. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param op the locking operation, see flock(2) - */ - void (*flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - int op); - - /** - * Allocate requested space. If this function returns success then - * subsequent writes to the specified range shall not fail due to the lack - * of free space on the file system storage media. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future fallocate() requests will fail with EOPNOTSUPP without being - * send to the filesystem process. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param offset starting point for allocated region - * @param length size of allocated region - * @param mode determines the operation to be performed on the given range, - * see fallocate(2) - */ - void (*fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, - off_t length, struct fuse_file_info *fi); - - /** - * Read directory with attributes - * - * Send a buffer filled using fuse_add_direntry_plus(), with size not - * exceeding the requested size. Send an empty buffer on end of - * stream. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * In contrast to readdir() (which does not affect the lookup counts), - * the lookup count of every entry returned by readdirplus(), except "." - * and "..", is incremented by one. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_data - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum number of bytes to send - * @param off offset to continue reading the directory stream - * @param fi file information - */ - void (*readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Copy a range of data from one file to another - * - * Performs an optimized copy between two file descriptors without the - * additional cost of transferring data through the FUSE kernel module - * to user space (glibc) and then back into the FUSE filesystem again. - * - * In case this method is not implemented, glibc falls back to reading - * data from the source and writing to the destination. Effectively - * doing an inefficient copy of the data. - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure with error code EOPNOTSUPP, i.e. all - * future copy_file_range() requests will fail with EOPNOTSUPP without - * being send to the filesystem process. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino_in the inode number or the source file - * @param off_in starting point from were the data should be read - * @param fi_in file information of the source file - * @param ino_out the inode number or the destination file - * @param off_out starting point where the data should be written - * @param fi_out file information of the destination file - * @param len maximum size of the data to copy - * @param flags passed along with the copy_file_range() syscall - */ - void (*copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, - struct fuse_file_info *fi_in, fuse_ino_t ino_out, - off_t off_out, struct fuse_file_info *fi_out, - size_t len, int flags); - - /** - * Find next data or hole after the specified offset - * - * If this request is answered with an error code of ENOSYS, this is - * treated as a permanent failure, i.e. all future lseek() requests will - * fail with the same error code without being send to the filesystem - * process. - * - * Valid replies: - * fuse_reply_lseek - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param off offset to start search from - * @param whence either SEEK_DATA or SEEK_HOLE - * @param fi file information - */ - void (*lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, - struct fuse_file_info *fi); - - /** - * Synchronize file system content - * - * If this request is answered with an error code of ENOSYS, - * this is treated as success and future calls to syncfs() will - * succeed automatically without being sent to the filesystem - * process. - * - * @param req request handle - * @param ino the inode number - */ - void (*syncfs)(fuse_req_t req, fuse_ino_t ino); -}; - -/** - * Reply with an error code or success. - * - * Possible requests: - * all except forget - * - * Whereever possible, error codes should be chosen from the list of - * documented error conditions in the corresponding system calls - * manpage. - * - * An error code of ENOSYS is sometimes treated specially. This is - * indicated in the documentation of the affected handler functions. - * - * The following requests may be answered with a zero error code: - * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, - * removexattr, setlk. - * - * @param req request handle - * @param err the positive error value, or zero for success - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_err(fuse_req_t req, int err); - -/** - * Don't send reply - * - * Possible requests: - * forget - * forget_multi - * retrieve_reply - * - * @param req request handle - */ -void fuse_reply_none(fuse_req_t req); - -/** - * Reply with a directory entry - * - * Possible requests: - * lookup, mknod, mkdir, symlink, link - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); - -/** - * Reply with a directory entry and open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * create - * - * Side effects: - * increments the lookup count on success - * - * @param req request handle - * @param e the entry parameters - * @param fi file information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *fi); - -/** - * Reply with attributes - * - * Possible requests: - * getattr, setattr - * - * @param req request handle - * @param attr the attributes - * @param attr_timeout validity timeout (in seconds) for the attributes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout); - -/** - * Reply with the contents of a symbolic link - * - * Possible requests: - * readlink - * - * @param req request handle - * @param link symbolic link contents - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_readlink(fuse_req_t req, const char *link); - -/** - * Reply with open parameters - * - * currently the following members of 'fi' are used: - * fh, direct_io, keep_cache - * - * Possible requests: - * open, opendir - * - * @param req request handle - * @param fi file information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); - -/** - * Reply with number of bytes written - * - * Possible requests: - * write - * - * @param req request handle - * @param count the number of bytes written - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_write(fuse_req_t req, size_t count); - -/** - * Reply with data - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param buf buffer containing data - * @param size the size of data in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); - -/** - * Reply with data copied/moved from buffer(s) - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * Side effects: - * when used to return data from a readdirplus() (but not readdir()) - * call, increments the lookup count of each returned entry by one - * on success. - * - * @param req request handle - * @param bufv buffer vector - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv); - -/** - * Reply with data vector - * - * Possible requests: - * read, readdir, getxattr, listxattr - * - * @param req request handle - * @param iov the vector containing the data - * @param count the size of vector - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count); - -/** - * Reply with filesystem statistics - * - * Possible requests: - * statfs - * - * @param req request handle - * @param stbuf filesystem statistics - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf); - -/** - * Reply with needed buffer size - * - * Possible requests: - * getxattr, listxattr - * - * @param req request handle - * @param count the buffer size needed in bytes - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_xattr(fuse_req_t req, size_t count); - -/** - * Reply with file lock information - * - * Possible requests: - * getlk - * - * @param req request handle - * @param lock the lock information - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_lock(fuse_req_t req, const struct flock *lock); - -/** - * Reply with block index - * - * Possible requests: - * bmap - * - * @param req request handle - * @param idx block index within device - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_bmap(fuse_req_t req, uint64_t idx); - -/* - * Filling a buffer in readdir - */ - -/** - * Add a directory entry to the buffer - * - * Buffer needs to be large enough to hold the entry. If it's not, - * then the entry is not filled in but the size of the entry is still - * returned. The caller can check this by comparing the bufsize - * parameter with the returned entry size. If the entry size is - * larger than the buffer size, the operation failed. - * - * From the 'stbuf' argument the st_ino field and bits 12-15 of the - * st_mode field are used. The other fields are ignored. - * - * *off* should be any non-zero value that the filesystem can use to - * identify the current point in the directory stream. It does not - * need to be the actual physical position. A value of zero is - * reserved to mean "from the beginning", and should therefore never - * be used (the first call to fuse_add_direntry should be passed the - * offset of the second directory entry). - * - * @param req request handle - * @param buf the point where the new entry will be added to the buffer - * @param bufsize remaining size of the buffer - * @param name the name of the entry - * @param stbuf the file attributes - * @param off the offset of the next entry - * @return the space needed for the entry - */ -size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, - const char *name, const struct stat *stbuf, off_t off); - -/** - * Add a directory entry to the buffer with the attributes - * - * See documentation of `fuse_add_direntry()` for more details. - * - * @param req request handle - * @param buf the point where the new entry will be added to the buffer - * @param bufsize remaining size of the buffer - * @param name the name of the entry - * @param e the directory entry - * @param off the offset of the next entry - * @return the space needed for the entry - */ -size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, - const char *name, - const struct fuse_entry_param *e, off_t off); - -/** - * Reply to ask for data fetch and output buffer preparation. ioctl - * will be retried with the specified input data fetched and output - * buffer prepared. - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param in_iov iovec specifying data to fetch from the caller - * @param in_count number of entries in in_iov - * @param out_iov iovec specifying addresses to write output to - * @param out_count number of entries in out_iov - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, - size_t in_count, const struct iovec *out_iov, - size_t out_count); - -/** - * Reply to finish ioctl - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param buf buffer containing output data - * @param size length of output data - */ -int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size); - -/** - * Reply to finish ioctl with iov buffer - * - * Possible requests: - * ioctl - * - * @param req request handle - * @param result result to be passed to the caller - * @param iov the vector containing the data - * @param count the size of vector - */ -int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, - int count); - -/** - * Reply with poll result event mask - * - * @param req request handle - * @param revents poll result event mask - */ -int fuse_reply_poll(fuse_req_t req, unsigned revents); - -/** - * Reply with offset - * - * Possible requests: - * lseek - * - * @param req request handle - * @param off offset of next data or hole - * @return zero for success, -errno for failure to send reply - */ -int fuse_reply_lseek(fuse_req_t req, off_t off); - -/* - * Notification - */ - -/** - * Notify IO readiness event - * - * For more information, please read comment for poll operation. - * - * @param ph poll handle to notify IO readiness event for - */ -int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph); - -/** - * Notify to invalidate cache for an inode. - * - * Added in FUSE protocol version 7.12. If the kernel does not support - * this (or a newer) version, the function will return -ENOSYS and do - * nothing. - * - * If the filesystem has writeback caching enabled, invalidating an - * inode will first trigger a writeback of all dirty pages. The call - * will block until all writeback requests have completed and the - * inode has been invalidated. It will, however, not wait for - * completion of pending writeback requests that have been issued - * before. - * - * If there are no dirty pages, this function will never block. - * - * @param se the session object - * @param ino the inode number - * @param off the offset in the inode where to start invalidating - * or negative to invalidate attributes only - * @param len the amount of cache to invalidate or 0 for all - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, - off_t off, off_t len); - -/** - * Notify to invalidate parent attributes and the dentry matching - * parent/name - * - * To avoid a deadlock this function must not be called in the - * execution path of a related filesystem operation or within any code - * that could hold a lock that could be needed to execute such an - * operation. As of kernel 4.18, a "related operation" is a lookup(), - * symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() - * request for the parent, and a setattr(), unlink(), rmdir(), - * rename(), setxattr(), removexattr(), readdir() or readdirplus() - * request for the inode itself. - * - * When called correctly, this function will never block. - * - * Added in FUSE protocol version 7.12. If the kernel does not support - * this (or a newer) version, the function will return -ENOSYS and do - * nothing. - * - * @param se the session object - * @param parent inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, - const char *name, size_t namelen); - -/** - * This function behaves like fuse_lowlevel_notify_inval_entry() with - * the following additional effect (at least as of Linux kernel 4.8): - * - * If the provided *child* inode matches the inode that is currently - * associated with the cached dentry, and if there are any inotify - * watches registered for the dentry, then the watchers are informed - * that the dentry has been deleted. - * - * To avoid a deadlock this function must not be called while - * executing a related filesystem operation or while holding a lock - * that could be needed to execute such an operation (see the - * description of fuse_lowlevel_notify_inval_entry() for more - * details). - * - * When called correctly, this function will never block. - * - * Added in FUSE protocol version 7.18. If the kernel does not support - * this (or a newer) version, the function will return -ENOSYS and do - * nothing. - * - * @param se the session object - * @param parent inode number - * @param child inode number - * @param name file name - * @param namelen strlen() of file name - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, - fuse_ino_t child, const char *name, - size_t namelen); - -/** - * Store data to the kernel buffers - * - * Synchronously store data in the kernel buffers belonging to the - * given inode. The stored data is marked up-to-date (no read will be - * performed against it, unless it's invalidated or evicted from the - * cache). - * - * If the stored data overflows the current file size, then the size - * is extended, similarly to a write(2) on the filesystem. - * - * If this function returns an error, then the store wasn't fully - * completed, but it may have been partially completed. - * - * Added in FUSE protocol version 7.15. If the kernel does not support - * this (or a newer) version, the function will return -ENOSYS and do - * nothing. - * - * @param se the session object - * @param ino the inode number - * @param offset the starting offset into the file to store to - * @param bufv buffer vector - * @return zero for success, -errno for failure - */ -int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, - off_t offset, struct fuse_bufvec *bufv); - -/* - * Utility functions - */ - -/** - * Get the userdata from the request - * - * @param req request handle - * @return the user data passed to fuse_session_new() - */ -void *fuse_req_userdata(fuse_req_t req); - -/** - * Get the context from the request - * - * The pointer returned by this function will only be valid for the - * request's lifetime - * - * @param req request handle - * @return the context structure - */ -const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); - -/** - * Callback function for an interrupt - * - * @param req interrupted request - * @param data user data - */ -typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); - -/** - * Register/unregister callback for an interrupt - * - * If an interrupt has already happened, then the callback function is - * called from within this function, hence it's not possible for - * interrupts to be lost. - * - * @param req request handle - * @param func the callback function or NULL for unregister - * @param data user data passed to the callback function - */ -void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data); - -/** - * Check if a request has already been interrupted - * - * @param req request handle - * @return 1 if the request has been interrupted, 0 otherwise - */ -int fuse_req_interrupted(fuse_req_t req); - -/** - * Check if the session is connected via virtio - * - * @param se session object - * @return 1 if the session is a virtio session - */ -int fuse_lowlevel_is_virtio(struct fuse_session *se); - -/* - * Inquiry functions - */ - -/** - * Print low-level version information to stdout. - */ -void fuse_lowlevel_version(void); - -/** - * Print available low-level options to stdout. This is not an - * exhaustive list, but includes only those options that may be of - * interest to an end-user of a file system. - */ -void fuse_lowlevel_help(void); - -/** - * Print available options for `fuse_parse_cmdline()`. - */ -void fuse_cmdline_help(void); - -/* - * Filesystem setup & teardown - */ - -struct fuse_cmdline_opts { - int foreground; - int debug; - int nodefault_subtype; - int show_version; - int show_help; - int print_capabilities; - int syslog; - int log_level; - unsigned int max_idle_threads; - unsigned long rlimit_nofile; -}; - -/** - * Utility function to parse common options for simple file systems - * using the low-level API. A help text that describes the available - * options can be printed with `fuse_cmdline_help`. A single - * non-option argument is treated as the mountpoint. Multiple - * non-option arguments will result in an error. - * - * If neither -o subtype= or -o fsname= options are given, a new - * subtype option will be added and set to the basename of the program - * (the fsname will remain unset, and then defaults to "fuse"). - * - * Known options will be removed from *args*, unknown options will - * remain. - * - * @param args argument vector (input+output) - * @param opts output argument for parsed options - * @return 0 on success, -1 on failure - */ -int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts); - -/** - * Create a low level session. - * - * Returns a session structure suitable for passing to - * fuse_session_mount() and fuse_session_loop(). - * - * This function accepts most file-system independent mount options - * (like context, nodev, ro - see mount(8)), as well as the general - * fuse mount options listed in mount.fuse(8) (e.g. -o allow_root and - * -o default_permissions, but not ``-o use_ino``). Instead of `-o - * debug`, debugging may also enabled with `-d` or `--debug`. - * - * If not all options are known, an error message is written to stderr - * and the function returns NULL. - * - * Option parsing skips argv[0], which is assumed to contain the - * program name. To prevent accidentally passing an option in - * argv[0], this element must always be present (even if no options - * are specified). It may be set to the empty string ('\0') if no - * reasonable value can be provided. - * - * @param args argument vector - * @param op the (low-level) filesystem operations - * @param op_size sizeof(struct fuse_lowlevel_ops) - * @param userdata user data - * - * @return the fuse session on success, NULL on failure - **/ -struct fuse_session *fuse_session_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); - -/** - * Mount a FUSE file system. - * - * @param se session object - * - * @return 0 on success, -1 on failure. - **/ -int fuse_session_mount(struct fuse_session *se); - -/** - * Enter a single threaded, blocking event loop. - * - * When the event loop terminates because the connection to the FUSE - * kernel module has been closed, this function returns zero. This - * happens when the filesystem is unmounted regularly (by the - * filesystem owner or root running the umount(8) or fusermount(1) - * command), or if connection is explicitly severed by writing ``1`` - * to the``abort`` file in ``/sys/fs/fuse/connections/NNN``. The only - * way to distinguish between these two conditions is to check if the - * filesystem is still mounted after the session loop returns. - * - * When some error occurs during request processing, the function - * returns a negated errno(3) value. - * - * If the loop has been terminated because of a signal handler - * installed by fuse_set_signal_handlers(), this function returns the - * (positive) signal value that triggered the exit. - * - * @param se the session - * @return 0, -errno, or a signal value - */ -int fuse_session_loop(struct fuse_session *se); - -/** - * Flag a session as terminated. - * - * This function is invoked by the POSIX signal handlers, when - * registered using fuse_set_signal_handlers(). It will cause any - * running event loops to terminate on the next opportunity. - * - * @param se the session - */ -void fuse_session_exit(struct fuse_session *se); - -/** - * Reset the terminated flag of a session - * - * @param se the session - */ -void fuse_session_reset(struct fuse_session *se); - -/** - * Query the terminated flag of a session - * - * @param se the session - * @return 1 if exited, 0 if not exited - */ -int fuse_session_exited(struct fuse_session *se); - -/** - * Ensure that file system is unmounted. - * - * In regular operation, the file system is typically unmounted by the - * user calling umount(8) or fusermount(1), which then terminates the - * FUSE session loop. However, the session loop may also terminate as - * a result of an explicit call to fuse_session_exit() (e.g. by a - * signal handler installed by fuse_set_signal_handler()). In this - * case the filesystem remains mounted, but any attempt to access it - * will block (while the filesystem process is still running) or give - * an ESHUTDOWN error (after the filesystem process has terminated). - * - * If the communication channel with the FUSE kernel module is still - * open (i.e., if the session loop was terminated by an explicit call - * to fuse_session_exit()), this function will close it and unmount - * the filesystem. If the communication channel has been closed by the - * kernel, this method will do (almost) nothing. - * - * NOTE: The above semantics mean that if the connection to the kernel - * is terminated via the ``/sys/fs/fuse/connections/NNN/abort`` file, - * this method will *not* unmount the filesystem. - * - * @param se the session - */ -void fuse_session_unmount(struct fuse_session *se); - -/** - * Destroy a session - * - * @param se the session - */ -void fuse_session_destroy(struct fuse_session *se); - -/* - * Custom event loop support - */ - -/** - * Return file descriptor for communication with kernel. - * - * The file selector can be used to integrate FUSE with a custom event - * loop. Whenever data is available for reading on the provided fd, - * the event loop should call `fuse_session_receive_buf` followed by - * `fuse_session_process_buf` to process the request. - * - * The returned file descriptor is valid until `fuse_session_unmount` - * is called. - * - * @param se the session - * @return a file descriptor - */ -int fuse_session_fd(struct fuse_session *se); - -/** - * Process a raw request supplied in a generic buffer - * - * The fuse_buf may contain a memory buffer or a pipe file descriptor. - * - * @param se the session - * @param buf the fuse_buf containing the request - */ -void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf); - -/** - * Read a raw request from the kernel into the supplied buffer. - * - * Depending on file system options, system capabilities, and request - * size the request is either read into a memory buffer or spliced - * into a temporary pipe. - * - * @param se the session - * @param buf the fuse_buf to store the request in - * @return the actual size of the raw request, or -errno on error - */ -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf); - -#endif /* FUSE_LOWLEVEL_H_ */ diff --git a/tools/virtiofsd/fuse_misc.h b/tools/virtiofsd/fuse_misc.h deleted file mode 100644 index f252baa752..0000000000 --- a/tools/virtiofsd/fuse_misc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include - -/* - * Versioned symbols cannot be used in some cases because it - * - confuse the dynamic linker in uClibc - * - not supported on MacOSX (in MachO binary format) - */ -#if (!defined(__UCLIBC__) && !defined(__APPLE__)) -#define FUSE_SYMVER(x) __asm__(x) -#else -#define FUSE_SYMVER(x) -#endif - -#ifndef USE_UCLIBC -#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL) -#else -/* Is this hack still needed? */ -static inline void fuse_mutex_init(pthread_mutex_t *mut) -{ - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); - pthread_mutex_init(mut, &attr); - pthread_mutexattr_destroy(&attr); -} -#endif - -#ifdef HAVE_STRUCT_STAT_ST_ATIM -/* Linux */ -#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) -#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) -#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) -#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val) -#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val) -#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val) -#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC) -/* FreeBSD */ -#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) -#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) -#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) -#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val) -#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val) -#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val) -#else -#define ST_ATIM_NSEC(stbuf) 0 -#define ST_CTIM_NSEC(stbuf) 0 -#define ST_MTIM_NSEC(stbuf) 0 -#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0) -#define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0) -#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0) -#endif diff --git a/tools/virtiofsd/fuse_opt.c b/tools/virtiofsd/fuse_opt.c deleted file mode 100644 index 9d371448e9..0000000000 --- a/tools/virtiofsd/fuse_opt.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * Implementation of option parsing routines (dealing with `struct - * fuse_args`). - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "fuse_opt.h" -#include "fuse_i.h" -#include "fuse_misc.h" - - -struct fuse_opt_context { - void *data; - const struct fuse_opt *opt; - fuse_opt_proc_t proc; - int argctr; - int argc; - char **argv; - struct fuse_args outargs; - char *opts; - int nonopt; -}; - -void fuse_opt_free_args(struct fuse_args *args) -{ - if (args) { - if (args->argv && args->allocated) { - int i; - for (i = 0; i < args->argc; i++) { - free(args->argv[i]); - } - free(args->argv); - } - args->argc = 0; - args->argv = NULL; - args->allocated = 0; - } -} - -static int alloc_failed(void) -{ - fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); - return -1; -} - -int fuse_opt_add_arg(struct fuse_args *args, const char *arg) -{ - char **newargv; - char *newarg; - - assert(!args->argv || args->allocated); - - newarg = strdup(arg); - if (!newarg) { - return alloc_failed(); - } - - newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); - if (!newargv) { - free(newarg); - return alloc_failed(); - } - - args->argv = newargv; - args->allocated = 1; - args->argv[args->argc++] = newarg; - args->argv[args->argc] = NULL; - return 0; -} - -static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos, - const char *arg) -{ - assert(pos <= args->argc); - if (fuse_opt_add_arg(args, arg) == -1) { - return -1; - } - - if (pos != args->argc - 1) { - char *newarg = args->argv[args->argc - 1]; - memmove(&args->argv[pos + 1], &args->argv[pos], - sizeof(char *) * (args->argc - pos - 1)); - args->argv[pos] = newarg; - } - return 0; -} - -int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) -{ - return fuse_opt_insert_arg_common(args, pos, arg); -} - -static int next_arg(struct fuse_opt_context *ctx, const char *opt) -{ - if (ctx->argctr + 1 >= ctx->argc) { - fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt); - return -1; - } - ctx->argctr++; - return 0; -} - -static int add_arg(struct fuse_opt_context *ctx, const char *arg) -{ - return fuse_opt_add_arg(&ctx->outargs, arg); -} - -static int add_opt_common(char **opts, const char *opt, int esc) -{ - unsigned oldlen = *opts ? strlen(*opts) : 0; - char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1); - - if (!d) { - return alloc_failed(); - } - - *opts = d; - if (oldlen) { - d += oldlen; - *d++ = ','; - } - - for (; *opt; opt++) { - if (esc && (*opt == ',' || *opt == '\\')) { - *d++ = '\\'; - } - *d++ = *opt; - } - *d = '\0'; - - return 0; -} - -int fuse_opt_add_opt(char **opts, const char *opt) -{ - return add_opt_common(opts, opt, 0); -} - -int fuse_opt_add_opt_escaped(char **opts, const char *opt) -{ - return add_opt_common(opts, opt, 1); -} - -static int add_opt(struct fuse_opt_context *ctx, const char *opt) -{ - return add_opt_common(&ctx->opts, opt, 1); -} - -static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, - int iso) -{ - if (key == FUSE_OPT_KEY_DISCARD) { - return 0; - } - - if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { - int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); - if (res == -1 || !res) { - return res; - } - } - if (iso) { - return add_opt(ctx, arg); - } else { - return add_arg(ctx, arg); - } -} - -static int match_template(const char *t, const char *arg, unsigned *sepp) -{ - int arglen = strlen(arg); - const char *sep = strchr(t, '='); - sep = sep ? sep : strchr(t, ' '); - if (sep && (!sep[1] || sep[1] == '%')) { - int tlen = sep - t; - if (sep[0] == '=') { - tlen++; - } - if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { - *sepp = sep - t; - return 1; - } - } - if (strcmp(t, arg) == 0) { - *sepp = 0; - return 1; - } - return 0; -} - -static const struct fuse_opt *find_opt(const struct fuse_opt *opt, - const char *arg, unsigned *sepp) -{ - for (; opt && opt->templ; opt++) { - if (match_template(opt->templ, arg, sepp)) { - return opt; - } - } - return NULL; -} - -int fuse_opt_match(const struct fuse_opt *opts, const char *opt) -{ - unsigned dummy; - return find_opt(opts, opt, &dummy) ? 1 : 0; -} - -static int process_opt_param(void *var, const char *format, const char *param, - const char *arg) -{ - assert(format[0] == '%'); - if (format[1] == 's') { - char **s = var; - char *copy = strdup(param); - if (!copy) { - return alloc_failed(); - } - - free(*s); - *s = copy; - } else { - if (sscanf(param, format, var) != 1) { - fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", - arg); - return -1; - } - } - return 0; -} - -static int process_opt(struct fuse_opt_context *ctx, const struct fuse_opt *opt, - unsigned sep, const char *arg, int iso) -{ - if (opt->offset == -1U) { - if (call_proc(ctx, arg, opt->value, iso) == -1) { - return -1; - } - } else { - void *var = (char *)ctx->data + opt->offset; - if (sep && opt->templ[sep + 1]) { - const char *param = arg + sep; - if (opt->templ[sep] == '=') { - param++; - } - if (process_opt_param(var, opt->templ + sep + 1, param, arg) == - -1) { - return -1; - } - } else { - *(int *)var = opt->value; - } - } - return 0; -} - -static int process_opt_sep_arg(struct fuse_opt_context *ctx, - const struct fuse_opt *opt, unsigned sep, - const char *arg, int iso) -{ - int res; - char *newarg; - char *param; - - if (next_arg(ctx, arg) == -1) { - return -1; - } - - param = ctx->argv[ctx->argctr]; - newarg = g_try_malloc(sep + strlen(param) + 1); - if (!newarg) { - return alloc_failed(); - } - - memcpy(newarg, arg, sep); - strcpy(newarg + sep, param); - res = process_opt(ctx, opt, sep, newarg, iso); - g_free(newarg); - - return res; -} - -static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) -{ - unsigned sep; - const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); - if (opt) { - for (; opt; opt = find_opt(opt + 1, arg, &sep)) { - int res; - if (sep && opt->templ[sep] == ' ' && !arg[sep]) { - res = process_opt_sep_arg(ctx, opt, sep, arg, iso); - } else { - res = process_opt(ctx, opt, sep, arg, iso); - } - if (res == -1) { - return -1; - } - } - return 0; - } else { - return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); - } -} - -static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) -{ - char *s = opts; - char *d = s; - int end = 0; - - while (!end) { - if (*s == '\0') { - end = 1; - } - if (*s == ',' || end) { - int res; - - *d = '\0'; - res = process_gopt(ctx, opts, 1); - if (res == -1) { - return -1; - } - d = opts; - } else { - if (s[0] == '\\' && s[1] != '\0') { - s++; - if (s[0] >= '0' && s[0] <= '3' && s[1] >= '0' && s[1] <= '7' && - s[2] >= '0' && s[2] <= '7') { - *d++ = (s[0] - '0') * 0100 + (s[1] - '0') * 0010 + - (s[2] - '0'); - s += 2; - } else { - *d++ = *s; - } - } else { - *d++ = *s; - } - } - s++; - } - - return 0; -} - -static int process_option_group(struct fuse_opt_context *ctx, const char *opts) -{ - int res; - char *copy = strdup(opts); - - if (!copy) { - fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); - return -1; - } - res = process_real_option_group(ctx, copy); - free(copy); - return res; -} - -static int process_one(struct fuse_opt_context *ctx, const char *arg) -{ - if (ctx->nonopt || arg[0] != '-') { - return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); - } else if (arg[1] == 'o') { - if (arg[2]) { - return process_option_group(ctx, arg + 2); - } else { - if (next_arg(ctx, arg) == -1) { - return -1; - } - - return process_option_group(ctx, ctx->argv[ctx->argctr]); - } - } else if (arg[1] == '-' && !arg[2]) { - if (add_arg(ctx, arg) == -1) { - return -1; - } - ctx->nonopt = ctx->outargs.argc; - return 0; - } else { - return process_gopt(ctx, arg, 0); - } -} - -static int opt_parse(struct fuse_opt_context *ctx) -{ - if (ctx->argc) { - if (add_arg(ctx, ctx->argv[0]) == -1) { - return -1; - } - } - - for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) { - if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) { - return -1; - } - } - - if (ctx->opts) { - if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || - fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) { - return -1; - } - } - - /* If option separator ("--") is the last argument, remove it */ - if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc && - strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) { - free(ctx->outargs.argv[ctx->outargs.argc - 1]); - ctx->outargs.argv[--ctx->outargs.argc] = NULL; - } - - return 0; -} - -int fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc) -{ - int res; - struct fuse_opt_context ctx = { - .data = data, - .opt = opts, - .proc = proc, - }; - - if (!args || !args->argv || !args->argc) { - return 0; - } - - ctx.argc = args->argc; - ctx.argv = args->argv; - - res = opt_parse(&ctx); - if (res != -1) { - struct fuse_args tmp = *args; - *args = ctx.outargs; - ctx.outargs = tmp; - } - free(ctx.opts); - fuse_opt_free_args(&ctx.outargs); - return res; -} diff --git a/tools/virtiofsd/fuse_opt.h b/tools/virtiofsd/fuse_opt.h deleted file mode 100644 index 8f59b4d301..0000000000 --- a/tools/virtiofsd/fuse_opt.h +++ /dev/null @@ -1,272 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB. - */ - -#ifndef FUSE_OPT_H_ -#define FUSE_OPT_H_ - -/** @file - * - * This file defines the option parsing interface of FUSE - */ - -/** - * Option description - * - * This structure describes a single option, and action associated - * with it, in case it matches. - * - * More than one such match may occur, in which case the action for - * each match is executed. - * - * There are three possible actions in case of a match: - * - * i) An integer (int or unsigned) variable determined by 'offset' is - * set to 'value' - * - * ii) The processing function is called, with 'value' as the key - * - * iii) An integer (any) or string (char *) variable determined by - * 'offset' is set to the value of an option parameter - * - * 'offset' should normally be either set to - * - * - 'offsetof(struct foo, member)' actions i) and iii) - * - * - -1 action ii) - * - * The 'offsetof()' macro is defined in the header. - * - * The template determines which options match, and also have an - * effect on the action. Normally the action is either i) or ii), but - * if a format is present in the template, then action iii) is - * performed. - * - * The types of templates are: - * - * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only - * themselves. Invalid values are "--" and anything beginning - * with "-o" - * - * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or - * the relevant option in a comma separated option list - * - * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) - * which have a parameter - * - * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform - * action iii). - * - * 5) "-x ", etc. Matches either "-xparam" or "-x param" as - * two separate arguments - * - * 6) "-x %s", etc. Combination of 4) and 5) - * - * If the format is "%s", memory is allocated for the string unlike with - * scanf(). The previous value (if non-NULL) stored at the this location is - * freed. - */ -struct fuse_opt { - /** Matching template and optional parameter formatting */ - const char *templ; - - /** - * Offset of variable within 'data' parameter of fuse_opt_parse() - * or -1 - */ - unsigned long offset; - - /** - * Value to set the variable to, or to be passed as 'key' to the - * processing function. Ignored if template has a format - */ - int value; -}; - -/** - * Key option. In case of a match, the processing function will be - * called with the specified key. - */ -#define FUSE_OPT_KEY(templ, key) \ - { \ - templ, -1U, key \ - } - -/** - * Last option. An array of 'struct fuse_opt' must end with a NULL - * template value - */ -#define FUSE_OPT_END \ - { \ - NULL, 0, 0 \ - } - -/** - * Argument list - */ -struct fuse_args { - /** Argument count */ - int argc; - - /** Argument vector. NULL terminated */ - char **argv; - - /** Is 'argv' allocated? */ - int allocated; -}; - -/** - * Initializer for 'struct fuse_args' - */ -#define FUSE_ARGS_INIT(argc, argv) \ - { \ - argc, argv, 0 \ - } - -/** - * Key value passed to the processing function if an option did not - * match any template - */ -#define FUSE_OPT_KEY_OPT -1 - -/** - * Key value passed to the processing function for all non-options - * - * Non-options are the arguments beginning with a character other than - * '-' or all arguments after the special '--' option - */ -#define FUSE_OPT_KEY_NONOPT -2 - -/** - * Special key value for options to keep - * - * Argument is not passed to processing function, but behave as if the - * processing function returned 1 - */ -#define FUSE_OPT_KEY_KEEP -3 - -/** - * Special key value for options to discard - * - * Argument is not passed to processing function, but behave as if the - * processing function returned zero - */ -#define FUSE_OPT_KEY_DISCARD -4 - -/** - * Processing function - * - * This function is called if - * - option did not match any 'struct fuse_opt' - * - argument is a non-option - * - option did match and offset was set to -1 - * - * The 'arg' parameter will always contain the whole argument or - * option including the parameter if exists. A two-argument option - * ("-x foo") is always converted to single argument option of the - * form "-xfoo" before this function is called. - * - * Options of the form '-ofoo' are passed to this function without the - * '-o' prefix. - * - * The return value of this function determines whether this argument - * is to be inserted into the output argument vector, or discarded. - * - * @param data is the user data passed to the fuse_opt_parse() function - * @param arg is the whole argument or option - * @param key determines why the processing function was called - * @param outargs the current output argument list - * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept - */ -typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, - struct fuse_args *outargs); - -/** - * Option parsing function - * - * If 'args' was returned from a previous call to fuse_opt_parse() or - * it was constructed from - * - * A NULL 'args' is equivalent to an empty argument vector - * - * A NULL 'opts' is equivalent to an 'opts' array containing a single - * end marker - * - * A NULL 'proc' is equivalent to a processing function always - * returning '1' - * - * @param args is the input and output argument list - * @param data is the user data - * @param opts is the option description array - * @param proc is the processing function - * @return -1 on error, 0 on success - */ -int fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc); - -/** - * Add an option to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_opt(char **opts, const char *opt); - -/** - * Add an option, escaping commas, to a comma separated option list - * - * @param opts is a pointer to an option list, may point to a NULL value - * @param opt is the option to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_opt_escaped(char **opts, const char *opt); - -/** - * Add an argument to a NULL terminated argument vector - * - * @param args is the structure containing the current argument list - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_add_arg(struct fuse_args *args, const char *arg); - -/** - * Add an argument at the specified position in a NULL terminated - * argument vector - * - * Adds the argument to the N-th position. This is useful for adding - * options at the beginning of the array which must not come after the - * special '--' option. - * - * @param args is the structure containing the current argument list - * @param pos is the position at which to add the argument - * @param arg is the new argument to add - * @return -1 on allocation error, 0 on success - */ -int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); - -/** - * Free the contents of argument list - * - * The structure itself is not freed - * - * @param args is the structure containing the argument list - */ -void fuse_opt_free_args(struct fuse_args *args); - - -/** - * Check if an option matches - * - * @param opts is the option description array - * @param opt is the option to match - * @return 1 if a match is found, 0 if not - */ -int fuse_opt_match(const struct fuse_opt opts[], const char *opt); - -#endif /* FUSE_OPT_H_ */ diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c deleted file mode 100644 index 1de46de1ce..0000000000 --- a/tools/virtiofsd/fuse_signals.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * Utility functions for setting signal handlers. - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "fuse_i.h" -#include "fuse_lowlevel.h" - - -static struct fuse_session *fuse_instance; - -static void exit_handler(int sig) -{ - if (fuse_instance) { - fuse_session_exit(fuse_instance); - if (sig <= 0) { - fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n"); - abort(); - } - fuse_instance->error = sig; - } -} - -static void do_nothing(int sig) -{ - (void)sig; -} - -static int set_one_signal_handler(int sig, void (*handler)(int), int remove) -{ - struct sigaction sa; - struct sigaction old_sa; - - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = remove ? SIG_DFL : handler; - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = 0; - - if (sigaction(sig, NULL, &old_sa) == -1) { - fuse_log(FUSE_LOG_ERR, "fuse: cannot get old signal handler: %s\n", - strerror(errno)); - return -1; - } - - if (old_sa.sa_handler == (remove ? handler : SIG_DFL) && - sigaction(sig, &sa, NULL) == -1) { - fuse_log(FUSE_LOG_ERR, "fuse: cannot set signal handler: %s\n", - strerror(errno)); - return -1; - } - return 0; -} - -int fuse_set_signal_handlers(struct fuse_session *se) -{ - /* - * If we used SIG_IGN instead of the do_nothing function, - * then we would be unable to tell if we set SIG_IGN (and - * thus should reset to SIG_DFL in fuse_remove_signal_handlers) - * or if it was already set to SIG_IGN (and should be left - * untouched. - */ - if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 || - set_one_signal_handler(SIGINT, exit_handler, 0) == -1 || - set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 || - set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1) { - return -1; - } - - fuse_instance = se; - return 0; -} - -void fuse_remove_signal_handlers(struct fuse_session *se) -{ - if (fuse_instance != se) { - fuse_log(FUSE_LOG_ERR, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - } else { - fuse_instance = NULL; - } - - set_one_signal_handler(SIGHUP, exit_handler, 1); - set_one_signal_handler(SIGINT, exit_handler, 1); - set_one_signal_handler(SIGTERM, exit_handler, 1); - set_one_signal_handler(SIGPIPE, do_nothing, 1); -} diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c deleted file mode 100644 index 9368e292e4..0000000000 --- a/tools/virtiofsd/fuse_virtio.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * virtio-fs glue for FUSE - * Copyright (C) 2018 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Dave Gilbert - * - * Implements the glue between libfuse and libvhost-user - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#include "qemu/osdep.h" -#include "qemu/iov.h" -#include "qapi/error.h" -#include "fuse_i.h" -#include "standard-headers/linux/fuse.h" -#include "fuse_misc.h" -#include "fuse_opt.h" -#include "fuse_virtio.h" - -#include -#include -#include -#include - -#include "libvhost-user.h" - -struct fv_VuDev; -struct fv_QueueInfo { - pthread_t thread; - /* - * This lock protects the VuVirtq preventing races between - * fv_queue_thread() and fv_queue_worker(). - */ - pthread_mutex_t vq_lock; - - struct fv_VuDev *virtio_dev; - - /* Our queue index, corresponds to array position */ - int qidx; - int kick_fd; - int kill_fd; /* For killing the thread */ -}; - -/* A FUSE request */ -typedef struct { - VuVirtqElement elem; - struct fuse_chan ch; - - /* Used to complete requests that involve no reply */ - bool reply_sent; -} FVRequest; - -/* - * We pass the dev element into libvhost-user - * and then use it to get back to the outer - * container for other data. - */ -struct fv_VuDev { - VuDev dev; - struct fuse_session *se; - - /* - * Either handle virtqueues or vhost-user protocol messages. Don't do - * both at the same time since that could lead to race conditions if - * virtqueues or memory tables change while another thread is accessing - * them. - * - * The assumptions are: - * 1. fv_queue_thread() reads/writes to virtqueues and only reads VuDev. - * 2. virtio_loop() reads/writes virtqueues and VuDev. - */ - pthread_rwlock_t vu_dispatch_rwlock; - - /* - * The following pair of fields are only accessed in the main - * virtio_loop - */ - size_t nqueues; - struct fv_QueueInfo **qi; -}; - -/* Callback from libvhost-user */ -static uint64_t fv_get_features(VuDev *dev) -{ - return 1ULL << VIRTIO_F_VERSION_1; -} - -/* Callback from libvhost-user */ -static void fv_set_features(VuDev *dev, uint64_t features) -{ -} - -/* - * Callback from libvhost-user if there's a new fd we're supposed to listen - * to, typically a queue kick? - */ -static void fv_set_watch(VuDev *dev, int fd, int condition, vu_watch_cb cb, - void *data) -{ - fuse_log(FUSE_LOG_WARNING, "%s: TODO! fd=%d\n", __func__, fd); -} - -/* - * Callback from libvhost-user if we're no longer supposed to listen on an fd - */ -static void fv_remove_watch(VuDev *dev, int fd) -{ - fuse_log(FUSE_LOG_WARNING, "%s: TODO! fd=%d\n", __func__, fd); -} - -/* Callback from libvhost-user to panic */ -static void fv_panic(VuDev *dev, const char *err) -{ - fuse_log(FUSE_LOG_ERR, "%s: libvhost-user: %s\n", __func__, err); - /* TODO: Allow reconnects?? */ - exit(EXIT_FAILURE); -} - -/* - * Copy from an iovec into a fuse_buf (memory only) - * Caller must ensure there is space - */ -static size_t copy_from_iov(struct fuse_buf *buf, size_t out_num, - const struct iovec *out_sg, - size_t max) -{ - void *dest = buf->mem; - size_t copied = 0; - - while (out_num && max) { - size_t onelen = out_sg->iov_len; - onelen = MIN(onelen, max); - memcpy(dest, out_sg->iov_base, onelen); - dest += onelen; - copied += onelen; - out_sg++; - out_num--; - max -= onelen; - } - - return copied; -} - -/* - * Skip 'skip' bytes in the iov; 'sg_1stindex' is set as - * the index for the 1st iovec to read data from, and - * 'sg_1stskip' is the number of bytes to skip in that entry. - * - * Returns True if there are at least 'skip' bytes in the iovec - * - */ -static bool skip_iov(const struct iovec *sg, size_t sg_size, - size_t skip, - size_t *sg_1stindex, size_t *sg_1stskip) -{ - size_t vec; - - for (vec = 0; vec < sg_size; vec++) { - if (sg[vec].iov_len > skip) { - *sg_1stskip = skip; - *sg_1stindex = vec; - - return true; - } - - skip -= sg[vec].iov_len; - } - - *sg_1stindex = vec; - *sg_1stskip = 0; - return skip == 0; -} - -/* - * Copy from one iov to another, the given number of bytes - * The caller must have checked sizes. - */ -static void copy_iov(struct iovec *src_iov, int src_count, - struct iovec *dst_iov, int dst_count, size_t to_copy) -{ - size_t dst_offset = 0; - /* Outer loop copies 'src' elements */ - while (to_copy) { - assert(src_count); - size_t src_len = src_iov[0].iov_len; - size_t src_offset = 0; - - if (src_len > to_copy) { - src_len = to_copy; - } - /* Inner loop copies contents of one 'src' to maybe multiple dst. */ - while (src_len) { - assert(dst_count); - size_t dst_len = dst_iov[0].iov_len - dst_offset; - if (dst_len > src_len) { - dst_len = src_len; - } - - memcpy(dst_iov[0].iov_base + dst_offset, - src_iov[0].iov_base + src_offset, dst_len); - src_len -= dst_len; - to_copy -= dst_len; - src_offset += dst_len; - dst_offset += dst_len; - - assert(dst_offset <= dst_iov[0].iov_len); - if (dst_offset == dst_iov[0].iov_len) { - dst_offset = 0; - dst_iov++; - dst_count--; - } - } - src_iov++; - src_count--; - } -} - -/* - * pthread_rwlock_rdlock() and pthread_rwlock_wrlock can fail if - * a deadlock condition is detected or the current thread already - * owns the lock. They can also fail, like pthread_rwlock_unlock(), - * if the mutex wasn't properly initialized. None of these are ever - * expected to happen. - */ -static void vu_dispatch_rdlock(struct fv_VuDev *vud) -{ - int ret = pthread_rwlock_rdlock(&vud->vu_dispatch_rwlock); - assert(ret == 0); -} - -static void vu_dispatch_wrlock(struct fv_VuDev *vud) -{ - int ret = pthread_rwlock_wrlock(&vud->vu_dispatch_rwlock); - assert(ret == 0); -} - -static void vu_dispatch_unlock(struct fv_VuDev *vud) -{ - int ret = pthread_rwlock_unlock(&vud->vu_dispatch_rwlock); - assert(ret == 0); -} - -static void vq_send_element(struct fv_QueueInfo *qi, VuVirtqElement *elem, - ssize_t len) -{ - struct fuse_session *se = qi->virtio_dev->se; - VuDev *dev = &se->virtio_dev->dev; - VuVirtq *q = vu_get_queue(dev, qi->qidx); - - vu_dispatch_rdlock(qi->virtio_dev); - pthread_mutex_lock(&qi->vq_lock); - vu_queue_push(dev, q, elem, len); - vu_queue_notify(dev, q); - pthread_mutex_unlock(&qi->vq_lock); - vu_dispatch_unlock(qi->virtio_dev); -} - -/* - * Called back by ll whenever it wants to send a reply/message back - * The 1st element of the iov starts with the fuse_out_header - * 'unique'==0 means it's a notify message. - */ -int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int count) -{ - FVRequest *req = container_of(ch, FVRequest, ch); - struct fv_QueueInfo *qi = ch->qi; - VuVirtqElement *elem = &req->elem; - int ret = 0; - - assert(count >= 1); - assert(iov[0].iov_len >= sizeof(struct fuse_out_header)); - - struct fuse_out_header *out = iov[0].iov_base; - /* TODO: Endianness! */ - - size_t tosend_len = iov_size(iov, count); - - /* unique == 0 is notification, which we don't support */ - assert(out->unique); - assert(!req->reply_sent); - - /* The 'in' part of the elem is to qemu */ - unsigned int in_num = elem->in_num; - struct iovec *in_sg = elem->in_sg; - size_t in_len = iov_size(in_sg, in_num); - fuse_log(FUSE_LOG_DEBUG, "%s: elem %d: with %d in desc of length %zd\n", - __func__, elem->index, in_num, in_len); - - /* - * The elem should have room for a 'fuse_out_header' (out from fuse) - * plus the data based on the len in the header. - */ - if (in_len < sizeof(struct fuse_out_header)) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for out_header\n", - __func__, elem->index); - ret = -E2BIG; - goto err; - } - if (in_len < tosend_len) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too small for data len %zd\n", - __func__, elem->index, tosend_len); - ret = -E2BIG; - goto err; - } - - copy_iov(iov, count, in_sg, in_num, tosend_len); - - vq_send_element(qi, elem, tosend_len); - req->reply_sent = true; - -err: - return ret; -} - -/* - * Callback from fuse_send_data_iov_* when it's virtio and the buffer - * is a single FD with FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK - * We need send the iov and then the buffer. - * Return 0 on success - */ -int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int count, struct fuse_bufvec *buf, - size_t len) -{ - FVRequest *req = container_of(ch, FVRequest, ch); - struct fv_QueueInfo *qi = ch->qi; - VuVirtqElement *elem = &req->elem; - int ret = 0; - g_autofree struct iovec *in_sg_cpy = NULL; - - assert(count >= 1); - assert(iov[0].iov_len >= sizeof(struct fuse_out_header)); - - struct fuse_out_header *out = iov[0].iov_base; - /* TODO: Endianness! */ - - size_t iov_len = iov_size(iov, count); - size_t tosend_len = iov_len + len; - - out->len = tosend_len; - - fuse_log(FUSE_LOG_DEBUG, "%s: count=%d len=%zd iov_len=%zd\n", __func__, - count, len, iov_len); - - /* unique == 0 is notification which we don't support */ - assert(out->unique); - - assert(!req->reply_sent); - - /* The 'in' part of the elem is to qemu */ - unsigned int in_num = elem->in_num; - struct iovec *in_sg = elem->in_sg; - size_t in_len = iov_size(in_sg, in_num); - fuse_log(FUSE_LOG_DEBUG, "%s: elem %d: with %d in desc of length %zd\n", - __func__, elem->index, in_num, in_len); - - /* - * The elem should have room for a 'fuse_out_header' (out from fuse) - * plus the data based on the len in the header. - */ - if (in_len < sizeof(struct fuse_out_header)) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for out_header\n", - __func__, elem->index); - return E2BIG; - } - if (in_len < tosend_len) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too small for data len %zd\n", - __func__, elem->index, tosend_len); - return E2BIG; - } - - /* TODO: Limit to 'len' */ - - /* First copy the header data from iov->in_sg */ - copy_iov(iov, count, in_sg, in_num, iov_len); - - /* - * Build a copy of the in_sg iov so we can skip bits in it, - * including changing the offsets - */ - in_sg_cpy = g_new(struct iovec, in_num); - memcpy(in_sg_cpy, in_sg, sizeof(struct iovec) * in_num); - /* These get updated as we skip */ - struct iovec *in_sg_ptr = in_sg_cpy; - unsigned int in_sg_cpy_count = in_num; - - /* skip over parts of in_sg that contained the header iov */ - iov_discard_front(&in_sg_ptr, &in_sg_cpy_count, iov_len); - - do { - fuse_log(FUSE_LOG_DEBUG, "%s: in_sg_cpy_count=%d len remaining=%zd\n", - __func__, in_sg_cpy_count, len); - - ret = preadv(buf->buf[0].fd, in_sg_ptr, in_sg_cpy_count, - buf->buf[0].pos); - - if (ret == -1) { - ret = errno; - if (ret == EINTR) { - continue; - } - fuse_log(FUSE_LOG_DEBUG, "%s: preadv failed (%m) len=%zd\n", - __func__, len); - return ret; - } - - if (!ret) { - /* EOF case? */ - fuse_log(FUSE_LOG_DEBUG, "%s: !ret len remaining=%zd\n", __func__, - len); - break; - } - fuse_log(FUSE_LOG_DEBUG, "%s: preadv ret=%d len=%zd\n", __func__, - ret, len); - - len -= ret; - /* Short read. Retry reading remaining bytes */ - if (len) { - fuse_log(FUSE_LOG_DEBUG, "%s: ret < len\n", __func__); - /* Skip over this much next time around */ - iov_discard_front(&in_sg_ptr, &in_sg_cpy_count, ret); - buf->buf[0].pos += ret; - } - } while (len); - - /* Need to fix out->len on EOF */ - if (len) { - struct fuse_out_header *out_sg = in_sg[0].iov_base; - - tosend_len -= len; - out_sg->len = tosend_len; - } - - vq_send_element(qi, elem, tosend_len); - req->reply_sent = true; - return 0; -} - -static __thread bool clone_fs_called; - -/* Process one FVRequest in a thread pool */ -static void fv_queue_worker(gpointer data, gpointer user_data) -{ - struct fv_QueueInfo *qi = user_data; - struct fuse_session *se = qi->virtio_dev->se; - FVRequest *req = data; - VuVirtqElement *elem = &req->elem; - struct fuse_buf fbuf = {}; - bool allocated_bufv = false; - struct fuse_bufvec bufv; - struct fuse_bufvec *pbufv; - struct fuse_in_header inh; - - assert(se->bufsize > sizeof(struct fuse_in_header)); - - if (!clone_fs_called) { - int ret; - - /* unshare FS for xattr operation */ - ret = unshare(CLONE_FS); - /* should not fail */ - assert(ret == 0); - - clone_fs_called = true; - } - - /* - * An element contains one request and the space to send our response - * They're spread over multiple descriptors in a scatter/gather set - * and we can't trust the guest to keep them still; so copy in/out. - */ - fbuf.mem = g_malloc(se->bufsize); - - fuse_mutex_init(&req->ch.lock); - req->ch.fd = -1; - req->ch.qi = qi; - - /* The 'out' part of the elem is from qemu */ - unsigned int out_num = elem->out_num; - struct iovec *out_sg = elem->out_sg; - size_t out_len = iov_size(out_sg, out_num); - fuse_log(FUSE_LOG_DEBUG, - "%s: elem %d: with %d out desc of length %zd\n", - __func__, elem->index, out_num, out_len); - - /* - * The elem should contain a 'fuse_in_header' (in to fuse) - * plus the data based on the len in the header. - */ - if (out_len < sizeof(struct fuse_in_header)) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for in_header\n", - __func__, elem->index); - assert(0); /* TODO */ - } - if (out_len > se->bufsize) { - fuse_log(FUSE_LOG_ERR, "%s: elem %d too large for buffer\n", __func__, - elem->index); - assert(0); /* TODO */ - } - /* Copy just the fuse_in_header and look at it */ - copy_from_iov(&fbuf, out_num, out_sg, - sizeof(struct fuse_in_header)); - memcpy(&inh, fbuf.mem, sizeof(struct fuse_in_header)); - - pbufv = NULL; /* Compiler thinks an unitialised path */ - if (inh.opcode == FUSE_WRITE && - out_len >= (sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in))) { - /* - * For a write we don't actually need to copy the - * data, we can just do it straight out of guest memory - * but we must still copy the headers in case the guest - * was nasty and changed them while we were using them. - */ - fuse_log(FUSE_LOG_DEBUG, "%s: Write special case\n", __func__); - - fbuf.size = copy_from_iov(&fbuf, out_num, out_sg, - sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in)); - /* That copy reread the in_header, make sure we use the original */ - memcpy(fbuf.mem, &inh, sizeof(struct fuse_in_header)); - - /* Allocate the bufv, with space for the rest of the iov */ - pbufv = g_try_malloc(sizeof(struct fuse_bufvec) + - sizeof(struct fuse_buf) * out_num); - if (!pbufv) { - fuse_log(FUSE_LOG_ERR, "%s: pbufv malloc failed\n", - __func__); - goto out; - } - - allocated_bufv = true; - pbufv->count = 1; - pbufv->buf[0] = fbuf; - - size_t iovindex, pbufvindex, iov_bytes_skip; - pbufvindex = 1; /* 2 headers, 1 fusebuf */ - - if (!skip_iov(out_sg, out_num, - sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in), - &iovindex, &iov_bytes_skip)) { - fuse_log(FUSE_LOG_ERR, "%s: skip failed\n", - __func__); - goto out; - } - - for (; iovindex < out_num; iovindex++, pbufvindex++) { - pbufv->count++; - pbufv->buf[pbufvindex].pos = ~0; /* Dummy */ - pbufv->buf[pbufvindex].flags = 0; - pbufv->buf[pbufvindex].mem = out_sg[iovindex].iov_base; - pbufv->buf[pbufvindex].size = out_sg[iovindex].iov_len; - - if (iov_bytes_skip) { - pbufv->buf[pbufvindex].mem += iov_bytes_skip; - pbufv->buf[pbufvindex].size -= iov_bytes_skip; - iov_bytes_skip = 0; - } - } - } else { - /* Normal (non fast write) path */ - - copy_from_iov(&fbuf, out_num, out_sg, se->bufsize); - /* That copy reread the in_header, make sure we use the original */ - memcpy(fbuf.mem, &inh, sizeof(struct fuse_in_header)); - fbuf.size = out_len; - - /* TODO! Endianness of header */ - - /* TODO: Add checks for fuse_session_exited */ - bufv.buf[0] = fbuf; - bufv.count = 1; - pbufv = &bufv; - } - pbufv->idx = 0; - pbufv->off = 0; - fuse_session_process_buf_int(se, pbufv, &req->ch); - -out: - if (allocated_bufv) { - g_free(pbufv); - } - - /* If the request has no reply, still recycle the virtqueue element */ - if (!req->reply_sent) { - fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n", __func__, - elem->index); - vq_send_element(qi, elem, 0); - } - - pthread_mutex_destroy(&req->ch.lock); - g_free(fbuf.mem); - free(req); -} - -/* Thread function for individual queues, created when a queue is 'started' */ -static void *fv_queue_thread(void *opaque) -{ - struct fv_QueueInfo *qi = opaque; - struct VuDev *dev = &qi->virtio_dev->dev; - struct VuVirtq *q = vu_get_queue(dev, qi->qidx); - struct fuse_session *se = qi->virtio_dev->se; - GThreadPool *pool = NULL; - GList *req_list = NULL; - - if (se->thread_pool_size) { - fuse_log(FUSE_LOG_DEBUG, "%s: Creating thread pool for Queue %d\n", - __func__, qi->qidx); - pool = g_thread_pool_new(fv_queue_worker, qi, se->thread_pool_size, - FALSE, NULL); - if (!pool) { - fuse_log(FUSE_LOG_ERR, "%s: g_thread_pool_new failed\n", __func__); - return NULL; - } - } - - fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__, - qi->qidx, qi->kick_fd); - while (1) { - struct pollfd pf[2]; - - pf[0].fd = qi->kick_fd; - pf[0].events = POLLIN; - pf[0].revents = 0; - pf[1].fd = qi->kill_fd; - pf[1].events = POLLIN; - pf[1].revents = 0; - - fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for Queue %d event\n", __func__, - qi->qidx); - int poll_res = ppoll(pf, 2, NULL, NULL); - - if (poll_res == -1) { - if (errno == EINTR) { - fuse_log(FUSE_LOG_INFO, "%s: ppoll interrupted, going around\n", - __func__); - continue; - } - fuse_log(FUSE_LOG_ERR, "fv_queue_thread ppoll: %m\n"); - break; - } - assert(poll_res >= 1); - if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { - fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x Queue %d\n", - __func__, pf[0].revents, qi->qidx); - break; - } - if (pf[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { - fuse_log(FUSE_LOG_ERR, - "%s: Unexpected poll revents %x Queue %d killfd\n", - __func__, pf[1].revents, qi->qidx); - break; - } - if (pf[1].revents) { - fuse_log(FUSE_LOG_INFO, "%s: kill event on queue %d - quitting\n", - __func__, qi->qidx); - break; - } - assert(pf[0].revents & POLLIN); - fuse_log(FUSE_LOG_DEBUG, "%s: Got queue event on Queue %d\n", __func__, - qi->qidx); - - eventfd_t evalue; - if (eventfd_read(qi->kick_fd, &evalue)) { - fuse_log(FUSE_LOG_ERR, "Eventfd_read for queue: %m\n"); - break; - } - /* Mutual exclusion with virtio_loop() */ - vu_dispatch_rdlock(qi->virtio_dev); - pthread_mutex_lock(&qi->vq_lock); - /* out is from guest, in is too guest */ - unsigned int in_bytes, out_bytes; - vu_queue_get_avail_bytes(dev, q, &in_bytes, &out_bytes, ~0, ~0); - - fuse_log(FUSE_LOG_DEBUG, - "%s: Queue %d gave evalue: %zx available: in: %u out: %u\n", - __func__, qi->qidx, (size_t)evalue, in_bytes, out_bytes); - - while (1) { - FVRequest *req = vu_queue_pop(dev, q, sizeof(FVRequest)); - if (!req) { - break; - } - - req->reply_sent = false; - - if (!se->thread_pool_size) { - req_list = g_list_prepend(req_list, req); - } else { - g_thread_pool_push(pool, req, NULL); - } - } - - pthread_mutex_unlock(&qi->vq_lock); - vu_dispatch_unlock(qi->virtio_dev); - - /* Process all the requests. */ - if (!se->thread_pool_size && req_list != NULL) { - req_list = g_list_reverse(req_list); - g_list_foreach(req_list, fv_queue_worker, qi); - g_list_free(req_list); - req_list = NULL; - } - } - - if (pool) { - g_thread_pool_free(pool, FALSE, TRUE); - } - - return NULL; -} - -static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx) -{ - int ret; - struct fv_QueueInfo *ourqi; - - assert(qidx < vud->nqueues); - ourqi = vud->qi[qidx]; - - /* Kill the thread */ - if (eventfd_write(ourqi->kill_fd, 1)) { - fuse_log(FUSE_LOG_ERR, "Eventfd_write for queue %d: %s\n", - qidx, strerror(errno)); - } - ret = pthread_join(ourqi->thread, NULL); - if (ret) { - fuse_log(FUSE_LOG_ERR, "%s: Failed to join thread idx %d err %d\n", - __func__, qidx, ret); - } - pthread_mutex_destroy(&ourqi->vq_lock); - close(ourqi->kill_fd); - ourqi->kick_fd = -1; - g_free(vud->qi[qidx]); - vud->qi[qidx] = NULL; -} - -static void stop_all_queues(struct fv_VuDev *vud) -{ - for (int i = 0; i < vud->nqueues; i++) { - if (!vud->qi[i]) { - continue; - } - - fuse_log(FUSE_LOG_INFO, "%s: Stopping queue %d thread\n", __func__, i); - fv_queue_cleanup_thread(vud, i); - } -} - -/* Callback from libvhost-user on start or stop of a queue */ -static void fv_queue_set_started(VuDev *dev, int qidx, bool started) -{ - struct fv_VuDev *vud = container_of(dev, struct fv_VuDev, dev); - struct fv_QueueInfo *ourqi; - - fuse_log(FUSE_LOG_INFO, "%s: qidx=%d started=%d\n", __func__, qidx, - started); - assert(qidx >= 0); - - /* - * Ignore additional request queues for now. passthrough_ll.c must be - * audited for thread-safety issues first. It was written with a - * well-behaved client in mind and may not protect against all types of - * races yet. - */ - if (qidx > 1) { - fuse_log(FUSE_LOG_ERR, - "%s: multiple request queues not yet implemented, please only " - "configure 1 request queue\n", - __func__); - exit(EXIT_FAILURE); - } - - if (started) { - /* Fire up a thread to watch this queue */ - if (qidx >= vud->nqueues) { - vud->qi = g_realloc_n(vud->qi, qidx + 1, sizeof(vud->qi[0])); - memset(vud->qi + vud->nqueues, 0, - sizeof(vud->qi[0]) * (1 + (qidx - vud->nqueues))); - vud->nqueues = qidx + 1; - } - if (!vud->qi[qidx]) { - vud->qi[qidx] = g_new0(struct fv_QueueInfo, 1); - vud->qi[qidx]->virtio_dev = vud; - vud->qi[qidx]->qidx = qidx; - } else { - /* Shouldn't have been started */ - assert(vud->qi[qidx]->kick_fd == -1); - } - ourqi = vud->qi[qidx]; - ourqi->kick_fd = dev->vq[qidx].kick_fd; - - ourqi->kill_fd = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE); - assert(ourqi->kill_fd != -1); - pthread_mutex_init(&ourqi->vq_lock, NULL); - - if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) { - fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n", - __func__, qidx); - assert(0); - } - } else { - /* - * Temporarily drop write-lock taken in virtio_loop() so that - * the queue thread doesn't block in virtio_send_msg(). - */ - vu_dispatch_unlock(vud); - fv_queue_cleanup_thread(vud, qidx); - vu_dispatch_wrlock(vud); - } -} - -static bool fv_queue_order(VuDev *dev, int qidx) -{ - return false; -} - -static const VuDevIface fv_iface = { - .get_features = fv_get_features, - .set_features = fv_set_features, - - /* Don't need process message, we've not got any at vhost-user level */ - .queue_set_started = fv_queue_set_started, - - .queue_is_processed_in_order = fv_queue_order, -}; - -/* - * Main loop; this mostly deals with events on the vhost-user - * socket itself, and not actual fuse data. - */ -int virtio_loop(struct fuse_session *se) -{ - fuse_log(FUSE_LOG_INFO, "%s: Entry\n", __func__); - - while (!fuse_session_exited(se)) { - struct pollfd pf[1]; - bool ok; - pf[0].fd = se->vu_socketfd; - pf[0].events = POLLIN; - pf[0].revents = 0; - - fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for VU event\n", __func__); - int poll_res = ppoll(pf, 1, NULL, NULL); - - if (poll_res == -1) { - if (errno == EINTR) { - fuse_log(FUSE_LOG_INFO, "%s: ppoll interrupted, going around\n", - __func__); - continue; - } - fuse_log(FUSE_LOG_ERR, "virtio_loop ppoll: %m\n"); - break; - } - assert(poll_res == 1); - if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { - fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x\n", __func__, - pf[0].revents); - break; - } - assert(pf[0].revents & POLLIN); - fuse_log(FUSE_LOG_DEBUG, "%s: Got VU event\n", __func__); - /* Mutual exclusion with fv_queue_thread() */ - vu_dispatch_wrlock(se->virtio_dev); - - ok = vu_dispatch(&se->virtio_dev->dev); - - vu_dispatch_unlock(se->virtio_dev); - - if (!ok) { - fuse_log(FUSE_LOG_ERR, "%s: vu_dispatch failed\n", __func__); - break; - } - } - - /* - * Make sure all fv_queue_thread()s quit on exit, as we're about to - * free virtio dev and fuse session, no one should access them anymore. - */ - stop_all_queues(se->virtio_dev); - fuse_log(FUSE_LOG_INFO, "%s: Exit\n", __func__); - - return 0; -} - -static void strreplace(char *s, char old, char new) -{ - for (; *s; ++s) { - if (*s == old) { - *s = new; - } - } -} - -static bool fv_socket_lock(struct fuse_session *se) -{ - g_autofree gchar *sk_name = NULL; - g_autofree gchar *pidfile = NULL; - g_autofree gchar *state = NULL; - g_autofree gchar *dir = NULL; - Error *local_err = NULL; - - state = qemu_get_local_state_dir(); - dir = g_build_filename(state, "run", "virtiofsd", NULL); - - if (g_mkdir_with_parents(dir, S_IRWXU) < 0) { - fuse_log(FUSE_LOG_ERR, "%s: Failed to create directory %s: %s\n", - __func__, dir, strerror(errno)); - return false; - } - - sk_name = g_strdup(se->vu_socket_path); - strreplace(sk_name, '/', '.'); - pidfile = g_strdup_printf("%s/%s.pid", dir, sk_name); - - if (!qemu_write_pidfile(pidfile, &local_err)) { - error_report_err(local_err); - return false; - } - - return true; -} - -static int fv_create_listen_socket(struct fuse_session *se) -{ - struct sockaddr_un un; - mode_t old_umask; - - /* Nothing to do if fd is already initialized */ - if (se->vu_listen_fd >= 0) { - return 0; - } - - if (strlen(se->vu_socket_path) >= sizeof(un.sun_path)) { - fuse_log(FUSE_LOG_ERR, "Socket path too long\n"); - return -1; - } - - if (!strlen(se->vu_socket_path)) { - fuse_log(FUSE_LOG_ERR, "Socket path is empty\n"); - return -1; - } - - /* Check the vu_socket_path is already used */ - if (!fv_socket_lock(se)) { - return -1; - } - - /* - * Create the Unix socket to communicate with qemu - * based on QEMU's vhost-user-bridge - */ - unlink(se->vu_socket_path); - strcpy(un.sun_path, se->vu_socket_path); - size_t addr_len = sizeof(un); - - int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (listen_sock == -1) { - fuse_log(FUSE_LOG_ERR, "vhost socket creation: %m\n"); - return -1; - } - un.sun_family = AF_UNIX; - - /* - * Unfortunately bind doesn't let you set the mask on the socket, - * so set umask appropriately and restore it later. - */ - if (se->vu_socket_group) { - old_umask = umask(S_IROTH | S_IWOTH | S_IXOTH); - } else { - old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | - S_IROTH | S_IWOTH | S_IXOTH); - } - if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) { - fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n"); - close(listen_sock); - umask(old_umask); - return -1; - } - if (se->vu_socket_group) { - struct group *g = getgrnam(se->vu_socket_group); - if (g) { - if (chown(se->vu_socket_path, -1, g->gr_gid) == -1) { - fuse_log(FUSE_LOG_WARNING, - "vhost socket failed to set group to %s (%d): %m\n", - se->vu_socket_group, g->gr_gid); - } - } else { - fuse_log(FUSE_LOG_ERR, - "vhost socket: unable to find group '%s'\n", - se->vu_socket_group); - close(listen_sock); - umask(old_umask); - return -1; - } - } - umask(old_umask); - - if (listen(listen_sock, 1) == -1) { - fuse_log(FUSE_LOG_ERR, "vhost socket listen: %m\n"); - close(listen_sock); - return -1; - } - - se->vu_listen_fd = listen_sock; - return 0; -} - -int virtio_session_mount(struct fuse_session *se) -{ - int ret; - - /* - * Test that unshare(CLONE_FS) works. fv_queue_worker() will need it. It's - * an unprivileged system call but some Docker/Moby versions are known to - * reject it via seccomp when CAP_SYS_ADMIN is not given. - * - * Note that the program is single-threaded here so this syscall has no - * visible effect and is safe to make. - */ - ret = unshare(CLONE_FS); - if (ret == -1 && errno == EPERM) { - fuse_log(FUSE_LOG_ERR, "unshare(CLONE_FS) failed with EPERM. If " - "running in a container please check that the container " - "runtime seccomp policy allows unshare.\n"); - return -1; - } - - ret = fv_create_listen_socket(se); - if (ret < 0) { - return ret; - } - - se->fd = -1; - - fuse_log(FUSE_LOG_INFO, "%s: Waiting for vhost-user socket connection...\n", - __func__); - int data_sock = accept(se->vu_listen_fd, NULL, NULL); - if (data_sock == -1) { - fuse_log(FUSE_LOG_ERR, "vhost socket accept: %m\n"); - close(se->vu_listen_fd); - return -1; - } - close(se->vu_listen_fd); - se->vu_listen_fd = -1; - fuse_log(FUSE_LOG_INFO, "%s: Received vhost-user socket connection\n", - __func__); - - /* TODO: Some cleanup/deallocation! */ - se->virtio_dev = g_new0(struct fv_VuDev, 1); - - se->vu_socketfd = data_sock; - se->virtio_dev->se = se; - pthread_rwlock_init(&se->virtio_dev->vu_dispatch_rwlock, NULL); - if (!vu_init(&se->virtio_dev->dev, 2, se->vu_socketfd, fv_panic, NULL, - fv_set_watch, fv_remove_watch, &fv_iface)) { - fuse_log(FUSE_LOG_ERR, "%s: vu_init failed\n", __func__); - return -1; - } - - return 0; -} - -void virtio_session_close(struct fuse_session *se) -{ - close(se->vu_socketfd); - - if (!se->virtio_dev) { - return; - } - - g_free(se->virtio_dev->qi); - pthread_rwlock_destroy(&se->virtio_dev->vu_dispatch_rwlock); - g_free(se->virtio_dev); - se->virtio_dev = NULL; -} diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h deleted file mode 100644 index 111684032c..0000000000 --- a/tools/virtiofsd/fuse_virtio.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * virtio-fs glue for FUSE - * Copyright (C) 2018 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Dave Gilbert - * - * Implements the glue between libfuse and libvhost-user - * - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB - */ - -#ifndef FUSE_VIRTIO_H -#define FUSE_VIRTIO_H - -#include "fuse_i.h" - -struct fuse_session; - -int virtio_session_mount(struct fuse_session *se); -void virtio_session_close(struct fuse_session *se); -int virtio_loop(struct fuse_session *se); - - -int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int count); - -int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, - struct iovec *iov, int count, - struct fuse_bufvec *buf, size_t len); - -#endif diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c deleted file mode 100644 index f5f66f292c..0000000000 --- a/tools/virtiofsd/helper.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * Helper functions to create (simple) standalone programs. With the - * aid of these functions it should be possible to create full FUSE - * file system by implementing nothing but the request handlers. - - * This program can be distributed under the terms of the GNU LGPLv2. - * See the file COPYING.LIB. - */ - -#include "qemu/osdep.h" -#include "fuse_i.h" -#include "fuse_lowlevel.h" -#include "fuse_misc.h" -#include "fuse_opt.h" - -#include -#include - -#define FUSE_HELPER_OPT(t, p) \ - { \ - t, offsetof(struct fuse_cmdline_opts, p), 1 \ - } -#define FUSE_HELPER_OPT_VALUE(t, p, v) \ - { \ - t, offsetof(struct fuse_cmdline_opts, p), v \ - } - -static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-h", show_help), - FUSE_HELPER_OPT("--help", show_help), - FUSE_HELPER_OPT("-V", show_version), - FUSE_HELPER_OPT("--version", show_version), - FUSE_HELPER_OPT("--print-capabilities", print_capabilities), - FUSE_HELPER_OPT("-d", debug), - FUSE_HELPER_OPT("debug", debug), - FUSE_HELPER_OPT("-d", foreground), - FUSE_HELPER_OPT("debug", foreground), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT_VALUE("--daemonize", foreground, 0), - FUSE_HELPER_OPT("fsname=", nodefault_subtype), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), - FUSE_HELPER_OPT("subtype=", nodefault_subtype), - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), - FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads), - FUSE_HELPER_OPT("--rlimit-nofile=%lu", rlimit_nofile), - FUSE_HELPER_OPT("--syslog", syslog), - FUSE_HELPER_OPT_VALUE("log_level=debug", log_level, FUSE_LOG_DEBUG), - FUSE_HELPER_OPT_VALUE("log_level=info", log_level, FUSE_LOG_INFO), - FUSE_HELPER_OPT_VALUE("log_level=warn", log_level, FUSE_LOG_WARNING), - FUSE_HELPER_OPT_VALUE("log_level=err", log_level, FUSE_LOG_ERR), - FUSE_OPT_END -}; - -struct fuse_conn_info_opts { - int atomic_o_trunc; - int no_remote_posix_lock; - int no_remote_flock; - int splice_write; - int splice_move; - int splice_read; - int no_splice_write; - int no_splice_move; - int no_splice_read; - int auto_inval_data; - int no_auto_inval_data; - int no_readdirplus; - int no_readdirplus_auto; - int async_dio; - int no_async_dio; - int writeback_cache; - int no_writeback_cache; - int async_read; - int sync_read; - unsigned max_write; - unsigned max_readahead; - unsigned max_background; - unsigned congestion_threshold; - unsigned time_gran; - int set_max_write; - int set_max_readahead; - int set_max_background; - int set_congestion_threshold; - int set_time_gran; -}; - -#define CONN_OPTION(t, p, v) \ - { \ - t, offsetof(struct fuse_conn_info_opts, p), v \ - } -static const struct fuse_opt conn_info_opt_spec[] = { - CONN_OPTION("max_write=%u", max_write, 0), - CONN_OPTION("max_write=", set_max_write, 1), - CONN_OPTION("max_readahead=%u", max_readahead, 0), - CONN_OPTION("max_readahead=", set_max_readahead, 1), - CONN_OPTION("max_background=%u", max_background, 0), - CONN_OPTION("max_background=", set_max_background, 1), - CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0), - CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1), - CONN_OPTION("sync_read", sync_read, 1), - CONN_OPTION("async_read", async_read, 1), - CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1), - CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1), - CONN_OPTION("no_remote_lock", no_remote_flock, 1), - CONN_OPTION("no_remote_flock", no_remote_flock, 1), - CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1), - CONN_OPTION("splice_write", splice_write, 1), - CONN_OPTION("no_splice_write", no_splice_write, 1), - CONN_OPTION("splice_move", splice_move, 1), - CONN_OPTION("no_splice_move", no_splice_move, 1), - CONN_OPTION("splice_read", splice_read, 1), - CONN_OPTION("no_splice_read", no_splice_read, 1), - CONN_OPTION("auto_inval_data", auto_inval_data, 1), - CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1), - CONN_OPTION("readdirplus=no", no_readdirplus, 1), - CONN_OPTION("readdirplus=yes", no_readdirplus, 0), - CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1), - CONN_OPTION("readdirplus=auto", no_readdirplus, 0), - CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0), - CONN_OPTION("async_dio", async_dio, 1), - CONN_OPTION("no_async_dio", no_async_dio, 1), - CONN_OPTION("writeback_cache", writeback_cache, 1), - CONN_OPTION("no_writeback_cache", no_writeback_cache, 1), - CONN_OPTION("time_gran=%u", time_gran, 0), - CONN_OPTION("time_gran=", set_time_gran, 1), - FUSE_OPT_END -}; - - -void fuse_cmdline_help(void) -{ - printf(" -h --help print help\n" - " -V --version print version\n" - " --print-capabilities print vhost-user.json\n" - " -d -o debug enable debug output (implies -f)\n" - " --syslog log to syslog (default stderr)\n" - " -f foreground operation\n" - " --daemonize run in background\n" - " -o cache= cache mode. could be one of \"auto, " - "always, none\"\n" - " default: auto\n" - " -o flock|no_flock enable/disable flock\n" - " default: no_flock\n" - " -o log_level= log level, default to \"info\"\n" - " level could be one of \"debug, " - "info, warn, err\"\n" - " -o max_idle_threads the maximum number of idle worker " - "threads\n" - " allowed (default: 10)\n" - " -o posix_lock|no_posix_lock\n" - " enable/disable remote posix lock\n" - " default: no_posix_lock\n" - " -o readdirplus|no_readdirplus\n" - " enable/disable readirplus\n" - " default: readdirplus except with " - "cache=none\n" - " -o sandbox=namespace|chroot\n" - " sandboxing mode:\n" - " - namespace: mount, pid, and net\n" - " namespaces with pivot_root(2)\n" - " into shared directory\n" - " - chroot: chroot(2) into shared\n" - " directory (use in containers)\n" - " default: namespace\n" - " -o timeout= I/O timeout (seconds)\n" - " default: depends on cache= option.\n" - " -o writeback|no_writeback enable/disable writeback cache\n" - " default: no_writeback\n" - " -o xattr|no_xattr enable/disable xattr\n" - " default: no_xattr\n" - " -o xattrmap= Enable xattr mapping (enables xattr)\n" - " is a string consists of a series of rules\n" - " e.g. -o xattrmap=:map::user.virtiofs.:\n" - " -o modcaps=CAPLIST Modify the list of capabilities\n" - " e.g. -o modcaps=+sys_admin:-chown\n" - " --rlimit-nofile= set maximum number of file descriptors\n" - " (0 leaves rlimit unchanged)\n" - " default: min(1000000, fs.file-max - 16384)\n" - " if the current rlimit is lower\n" - " -o allow_direct_io|no_allow_direct_io\n" - " retain/discard O_DIRECT flags passed down\n" - " to virtiofsd from guest applications.\n" - " default: no_allow_direct_io\n" - " -o announce_submounts Announce sub-mount points to the guest\n" - " -o posix_acl/no_posix_acl Enable/Disable posix_acl. (default: disabled)\n" - " -o security_label/no_security_label Enable/Disable security label. (default: disabled)\n" - " -o killpriv_v2/no_killpriv_v2\n" - " Enable/Disable FUSE_HANDLE_KILLPRIV_V2.\n" - " (default: enabled as long as client supports it)\n" - ); -} - -static int fuse_helper_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) -{ - (void)data; - (void)outargs; - - switch (key) { - case FUSE_OPT_KEY_NONOPT: - fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg); - return -1; - - default: - /* Pass through unknown options */ - return 1; - } -} - -static unsigned long get_default_rlimit_nofile(void) -{ - g_autofree gchar *file_max_str = NULL; - const rlim_t reserved_fds = 16384; /* leave at least this many fds free */ - rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */ - rlim_t file_max; - struct rlimit rlim; - - /* - * Reduce max_fds below the system-wide maximum, if necessary. This - * ensures there are fds available for other processes so we don't - * cause resource exhaustion. - */ - if (!g_file_get_contents("/proc/sys/fs/file-max", &file_max_str, - NULL, NULL)) { - fuse_log(FUSE_LOG_ERR, "can't read /proc/sys/fs/file-max\n"); - exit(1); - } - file_max = g_ascii_strtoull(file_max_str, NULL, 10); - if (file_max < 2 * reserved_fds) { - fuse_log(FUSE_LOG_ERR, - "The fs.file-max sysctl is too low (%lu) to allow a " - "reasonable number of open files.\n", - (unsigned long)file_max); - exit(1); - } - max_fds = MIN(file_max - reserved_fds, max_fds); - - if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { - fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n"); - exit(1); - } - - if (rlim.rlim_cur >= max_fds) { - return 0; /* we have more fds available than required! */ - } - return max_fds; -} - -int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts) -{ - memset(opts, 0, sizeof(struct fuse_cmdline_opts)); - - opts->max_idle_threads = 10; - opts->rlimit_nofile = get_default_rlimit_nofile(); - opts->foreground = 1; - - if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) == - -1) { - return -1; - } - - return 0; -} - - -int fuse_daemonize(int foreground) -{ - int ret = 0, rett; - if (!foreground) { - int nullfd; - int waiter[2]; - char completed; - - if (!g_unix_open_pipe(waiter, FD_CLOEXEC, NULL)) { - fuse_log(FUSE_LOG_ERR, "fuse_daemonize: pipe: %s\n", - strerror(errno)); - return -1; - } - - /* - * demonize current process by forking it and killing the - * parent. This makes current process as a child of 'init'. - */ - switch (fork()) { - case -1: - fuse_log(FUSE_LOG_ERR, "fuse_daemonize: fork: %s\n", - strerror(errno)); - return -1; - case 0: - break; - default: - _exit(read(waiter[0], &completed, - sizeof(completed) != sizeof(completed))); - } - - if (setsid() == -1) { - fuse_log(FUSE_LOG_ERR, "fuse_daemonize: setsid: %s\n", - strerror(errno)); - return -1; - } - - ret = chdir("/"); - - nullfd = open("/dev/null", O_RDWR, 0); - if (nullfd != -1) { - rett = dup2(nullfd, 0); - if (!ret) { - ret = rett; - } - rett = dup2(nullfd, 1); - if (!ret) { - ret = rett; - } - rett = dup2(nullfd, 2); - if (!ret) { - ret = rett; - } - if (nullfd > 2) { - close(nullfd); - } - } - - /* Propagate completion of daemon initialization */ - completed = 1; - rett = write(waiter[1], &completed, sizeof(completed)); - if (!ret) { - ret = rett; - } - close(waiter[0]); - close(waiter[1]); - } else { - ret = chdir("/"); - } - return ret; -} - -void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, - struct fuse_conn_info *conn) -{ - if (opts->set_max_write) { - conn->max_write = opts->max_write; - } - if (opts->set_max_background) { - conn->max_background = opts->max_background; - } - if (opts->set_congestion_threshold) { - conn->congestion_threshold = opts->congestion_threshold; - } - if (opts->set_time_gran) { - conn->time_gran = opts->time_gran; - } - if (opts->set_max_readahead) { - conn->max_readahead = opts->max_readahead; - } - -#define LL_ENABLE(cond, cap) \ - if (cond) \ - conn->want |= (cap) -#define LL_DISABLE(cond, cap) \ - if (cond) \ - conn->want &= ~(cap) - - LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ); - LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ); - - LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE); - LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE); - - LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE); - LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE); - - LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA); - LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA); - - LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS); - LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO); - - LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO); - LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO); - - LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE); - LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE); - - LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ); - LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ); - - LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS); - LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS); -} - -struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args) -{ - struct fuse_conn_info_opts *opts; - - opts = calloc(1, sizeof(struct fuse_conn_info_opts)); - if (opts == NULL) { - fuse_log(FUSE_LOG_ERR, "calloc failed\n"); - return NULL; - } - if (fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) { - free(opts); - return NULL; - } - return opts; -} diff --git a/tools/virtiofsd/passthrough_helpers.h b/tools/virtiofsd/passthrough_helpers.h deleted file mode 100644 index 0b98275ed5..0000000000 --- a/tools/virtiofsd/passthrough_helpers.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE - */ - -/* - * Creates files on the underlying file system in response to a FUSE_MKNOD - * operation - */ -static int mknod_wrapper(int dirfd, const char *path, const char *link, - int mode, dev_t rdev) -{ - int res; - - if (S_ISREG(mode)) { - res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode); - if (res >= 0) { - res = close(res); - } - } else if (S_ISDIR(mode)) { - res = mkdirat(dirfd, path, mode); - } else if (S_ISLNK(mode) && link != NULL) { - res = symlinkat(link, dirfd, path); - } else if (S_ISFIFO(mode)) { - res = mkfifoat(dirfd, path, mode); - } else { - res = mknodat(dirfd, path, mode, rdev); - } - - return res; -} diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c deleted file mode 100644 index 40ea2ed27f..0000000000 --- a/tools/virtiofsd/passthrough_ll.c +++ /dev/null @@ -1,4521 +0,0 @@ -/* - * FUSE: Filesystem in Userspace - * Copyright (C) 2001-2007 Miklos Szeredi - * - * This program can be distributed under the terms of the GNU GPLv2. - * See the file COPYING. - */ - -/* - * - * This file system mirrors the existing file system hierarchy of the - * system, starting at the root file system. This is implemented by - * just "passing through" all requests to the corresponding user-space - * libc functions. In contrast to passthrough.c and passthrough_fh.c, - * this implementation uses the low-level API. Its performance should - * be the least bad among the three, but many operations are not - * implemented. In particular, it is not possible to remove files (or - * directories) because the code necessary to defer actual removal - * until the file is not opened anymore would make the example much - * more complicated. - * - * When writeback caching is enabled (-o writeback mount option), it - * is only possible to write to files for which the mounting user has - * read permissions. This is because the writeback cache requires the - * kernel to be able to issue read requests for all files (which the - * passthrough filesystem cannot satisfy if it can't read the file in - * the underlying filesystem). - * - * Compile with: - * - * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o - * passthrough_ll - * - * ## Source code ## - * \include passthrough_ll.c - */ - -#include "qemu/osdep.h" -#include "qemu/timer.h" -#include "qemu-version.h" -#include "qemu/help-texts.h" -#include "fuse_virtio.h" -#include "fuse_log.h" -#include "fuse_lowlevel.h" -#include "standard-headers/linux/fuse.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qemu/cutils.h" -#include "passthrough_helpers.h" -#include "passthrough_seccomp.h" - -/* Keep track of inode posix locks for each owner. */ -struct lo_inode_plock { - uint64_t lock_owner; - int fd; /* fd for OFD locks */ -}; - -struct lo_map_elem { - union { - struct lo_inode *inode; - struct lo_dirp *dirp; - int fd; - ssize_t freelist; - }; - bool in_use; -}; - -/* Maps FUSE fh or ino values to internal objects */ -struct lo_map { - struct lo_map_elem *elems; - size_t nelems; - ssize_t freelist; -}; - -struct lo_key { - ino_t ino; - dev_t dev; - uint64_t mnt_id; -}; - -struct lo_inode { - int fd; - - /* - * Atomic reference count for this object. The nlookup field holds a - * reference and release it when nlookup reaches 0. - */ - gint refcount; - - struct lo_key key; - - /* - * This counter keeps the inode alive during the FUSE session. - * Incremented when the FUSE inode number is sent in a reply - * (FUSE_LOOKUP, FUSE_READDIRPLUS, etc). Decremented when an inode is - * released by a FUSE_FORGET request. - * - * Note that this value is untrusted because the client can manipulate - * it arbitrarily using FUSE_FORGET requests. - * - * Protected by lo->mutex. - */ - uint64_t nlookup; - - fuse_ino_t fuse_ino; - pthread_mutex_t plock_mutex; - GHashTable *posix_locks; /* protected by lo_inode->plock_mutex */ - - mode_t filetype; -}; - -struct lo_cred { - uid_t euid; - gid_t egid; - mode_t umask; -}; - -enum { - CACHE_NONE, - CACHE_AUTO, - CACHE_ALWAYS, -}; - -enum { - SANDBOX_NAMESPACE, - SANDBOX_CHROOT, -}; - -typedef struct xattr_map_entry { - char *key; - char *prepend; - unsigned int flags; -} XattrMapEntry; - -struct lo_data { - pthread_mutex_t mutex; - int sandbox; - int debug; - int writeback; - int flock; - int posix_lock; - int xattr; - char *xattrmap; - char *xattr_security_capability; - char *source; - char *modcaps; - double timeout; - int cache; - int timeout_set; - int readdirplus_set; - int readdirplus_clear; - int allow_direct_io; - int announce_submounts; - bool use_statx; - struct lo_inode root; - GHashTable *inodes; /* protected by lo->mutex */ - struct lo_map ino_map; /* protected by lo->mutex */ - struct lo_map dirp_map; /* protected by lo->mutex */ - struct lo_map fd_map; /* protected by lo->mutex */ - XattrMapEntry *xattr_map_list; - size_t xattr_map_nentries; - - /* An O_PATH file descriptor to /proc/self/fd/ */ - int proc_self_fd; - /* An O_PATH file descriptor to /proc/self/task/ */ - int proc_self_task; - int user_killpriv_v2, killpriv_v2; - /* If set, virtiofsd is responsible for setting umask during creation */ - bool change_umask; - int user_posix_acl, posix_acl; - /* Keeps track if /proc//attr/fscreate should be used or not */ - bool use_fscreate; - int user_security_label; -}; - -static const struct fuse_opt lo_opts[] = { - { "sandbox=namespace", - offsetof(struct lo_data, sandbox), - SANDBOX_NAMESPACE }, - { "sandbox=chroot", - offsetof(struct lo_data, sandbox), - SANDBOX_CHROOT }, - { "writeback", offsetof(struct lo_data, writeback), 1 }, - { "no_writeback", offsetof(struct lo_data, writeback), 0 }, - { "source=%s", offsetof(struct lo_data, source), 0 }, - { "flock", offsetof(struct lo_data, flock), 1 }, - { "no_flock", offsetof(struct lo_data, flock), 0 }, - { "posix_lock", offsetof(struct lo_data, posix_lock), 1 }, - { "no_posix_lock", offsetof(struct lo_data, posix_lock), 0 }, - { "xattr", offsetof(struct lo_data, xattr), 1 }, - { "no_xattr", offsetof(struct lo_data, xattr), 0 }, - { "xattrmap=%s", offsetof(struct lo_data, xattrmap), 0 }, - { "modcaps=%s", offsetof(struct lo_data, modcaps), 0 }, - { "timeout=%lf", offsetof(struct lo_data, timeout), 0 }, - { "timeout=", offsetof(struct lo_data, timeout_set), 1 }, - { "cache=none", offsetof(struct lo_data, cache), CACHE_NONE }, - { "cache=auto", offsetof(struct lo_data, cache), CACHE_AUTO }, - { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS }, - { "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 }, - { "no_readdirplus", offsetof(struct lo_data, readdirplus_clear), 1 }, - { "allow_direct_io", offsetof(struct lo_data, allow_direct_io), 1 }, - { "no_allow_direct_io", offsetof(struct lo_data, allow_direct_io), 0 }, - { "announce_submounts", offsetof(struct lo_data, announce_submounts), 1 }, - { "killpriv_v2", offsetof(struct lo_data, user_killpriv_v2), 1 }, - { "no_killpriv_v2", offsetof(struct lo_data, user_killpriv_v2), 0 }, - { "posix_acl", offsetof(struct lo_data, user_posix_acl), 1 }, - { "no_posix_acl", offsetof(struct lo_data, user_posix_acl), 0 }, - { "security_label", offsetof(struct lo_data, user_security_label), 1 }, - { "no_security_label", offsetof(struct lo_data, user_security_label), 0 }, - FUSE_OPT_END -}; -static bool use_syslog = false; -static int current_log_level; -static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode, - uint64_t n); - -static struct { - pthread_mutex_t mutex; - void *saved; -} cap; -/* That we loaded cap-ng in the current thread from the saved */ -static __thread bool cap_loaded = 0; - -static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st, - uint64_t mnt_id); -static int xattr_map_client(const struct lo_data *lo, const char *client_name, - char **out_name); - -#define FCHDIR_NOFAIL(fd) do { \ - int fchdir_res = fchdir(fd); \ - assert(fchdir_res == 0); \ - } while (0) - -static bool is_dot_or_dotdot(const char *name) -{ - return name[0] == '.' && - (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); -} - -/* Is `path` a single path component that is not "." or ".."? */ -static bool is_safe_path_component(const char *path) -{ - if (strchr(path, '/')) { - return false; - } - - return !is_dot_or_dotdot(path); -} - -static bool is_empty(const char *name) -{ - return name[0] == '\0'; -} - -static struct lo_data *lo_data(fuse_req_t req) -{ - return (struct lo_data *)fuse_req_userdata(req); -} - -/* - * Tries to figure out if /proc//attr/fscreate is usable or not. With - * selinux=0, read from fscreate returns -EINVAL. - * - * TODO: Link with libselinux and use is_selinux_enabled() instead down - * the line. It probably will be more reliable indicator. - */ -static bool is_fscreate_usable(struct lo_data *lo) -{ - char procname[64]; - int fscreate_fd; - size_t bytes_read; - - sprintf(procname, "%ld/attr/fscreate", syscall(SYS_gettid)); - fscreate_fd = openat(lo->proc_self_task, procname, O_RDWR); - if (fscreate_fd == -1) { - return false; - } - - bytes_read = read(fscreate_fd, procname, 64); - close(fscreate_fd); - if (bytes_read == -1) { - return false; - } - return true; -} - -/* Helpers to set/reset fscreate */ -static int open_set_proc_fscreate(struct lo_data *lo, const void *ctx, - size_t ctxlen, int *fd) -{ - char procname[64]; - int fscreate_fd, err = 0; - size_t written; - - sprintf(procname, "%ld/attr/fscreate", syscall(SYS_gettid)); - fscreate_fd = openat(lo->proc_self_task, procname, O_WRONLY); - err = fscreate_fd == -1 ? errno : 0; - if (err) { - return err; - } - - written = write(fscreate_fd, ctx, ctxlen); - err = written == -1 ? errno : 0; - if (err) { - goto out; - } - - *fd = fscreate_fd; - return 0; -out: - close(fscreate_fd); - return err; -} - -static void close_reset_proc_fscreate(int fd) -{ - if ((write(fd, NULL, 0)) == -1) { - fuse_log(FUSE_LOG_WARNING, "Failed to reset fscreate. err=%d\n", errno); - } - close(fd); - return; -} - -/* - * Load capng's state from our saved state if the current thread - * hadn't previously been loaded. - * returns 0 on success - */ -static int load_capng(void) -{ - if (!cap_loaded) { - pthread_mutex_lock(&cap.mutex); - capng_restore_state(&cap.saved); - /* - * restore_state free's the saved copy - * so make another. - */ - cap.saved = capng_save_state(); - if (!cap.saved) { - pthread_mutex_unlock(&cap.mutex); - fuse_log(FUSE_LOG_ERR, "capng_save_state (thread)\n"); - return -EINVAL; - } - pthread_mutex_unlock(&cap.mutex); - - /* - * We want to use the loaded state for our pid, - * not the original - */ - capng_setpid(syscall(SYS_gettid)); - cap_loaded = true; - } - return 0; -} - -/* - * Helpers for dropping and regaining effective capabilities. Returns 0 - * on success, error otherwise - */ -static int drop_effective_cap(const char *cap_name, bool *cap_dropped) -{ - int cap, ret; - - cap = capng_name_to_capability(cap_name); - if (cap < 0) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "capng_name_to_capability(%s) failed:%s\n", - cap_name, strerror(errno)); - goto out; - } - - if (load_capng()) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "load_capng() failed\n"); - goto out; - } - - /* We dont have this capability in effective set already. */ - if (!capng_have_capability(CAPNG_EFFECTIVE, cap)) { - ret = 0; - goto out; - } - - if (capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, cap)) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "capng_update(DROP,) failed\n"); - goto out; - } - - if (capng_apply(CAPNG_SELECT_CAPS)) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "drop:capng_apply() failed\n"); - goto out; - } - - ret = 0; - if (cap_dropped) { - *cap_dropped = true; - } - -out: - return ret; -} - -static int gain_effective_cap(const char *cap_name) -{ - int cap; - int ret = 0; - - cap = capng_name_to_capability(cap_name); - if (cap < 0) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "capng_name_to_capability(%s) failed:%s\n", - cap_name, strerror(errno)); - goto out; - } - - if (load_capng()) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "load_capng() failed\n"); - goto out; - } - - if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap)) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "capng_update(ADD,) failed\n"); - goto out; - } - - if (capng_apply(CAPNG_SELECT_CAPS)) { - ret = errno; - fuse_log(FUSE_LOG_ERR, "gain:capng_apply() failed\n"); - goto out; - } - ret = 0; - -out: - return ret; -} - -/* - * The host kernel normally drops security.capability xattr's on - * any write, however if we're remapping xattr names we need to drop - * whatever the clients security.capability is actually stored as. - */ -static int drop_security_capability(const struct lo_data *lo, int fd) -{ - if (!lo->xattr_security_capability) { - /* We didn't remap the name, let the host kernel do it */ - return 0; - } - if (!fremovexattr(fd, lo->xattr_security_capability)) { - /* All good */ - return 0; - } - - switch (errno) { - case ENODATA: - /* Attribute didn't exist, that's fine */ - return 0; - - case ENOTSUP: - /* FS didn't support attribute anyway, also fine */ - return 0; - - default: - /* Hmm other error */ - return errno; - } -} - -static void lo_map_init(struct lo_map *map) -{ - map->elems = NULL; - map->nelems = 0; - map->freelist = -1; -} - -static void lo_map_destroy(struct lo_map *map) -{ - g_free(map->elems); -} - -static int lo_map_grow(struct lo_map *map, size_t new_nelems) -{ - struct lo_map_elem *new_elems; - size_t i; - - if (new_nelems <= map->nelems) { - return 1; - } - - new_elems = g_try_realloc_n(map->elems, new_nelems, sizeof(map->elems[0])); - if (!new_elems) { - return 0; - } - - for (i = map->nelems; i < new_nelems; i++) { - new_elems[i].freelist = i + 1; - new_elems[i].in_use = false; - } - new_elems[new_nelems - 1].freelist = -1; - - map->elems = new_elems; - map->freelist = map->nelems; - map->nelems = new_nelems; - return 1; -} - -static struct lo_map_elem *lo_map_alloc_elem(struct lo_map *map) -{ - struct lo_map_elem *elem; - - if (map->freelist == -1 && !lo_map_grow(map, map->nelems + 256)) { - return NULL; - } - - elem = &map->elems[map->freelist]; - map->freelist = elem->freelist; - - elem->in_use = true; - - return elem; -} - -static struct lo_map_elem *lo_map_reserve(struct lo_map *map, size_t key) -{ - ssize_t *prev; - - if (!lo_map_grow(map, key + 1)) { - return NULL; - } - - for (prev = &map->freelist; *prev != -1; - prev = &map->elems[*prev].freelist) { - if (*prev == key) { - struct lo_map_elem *elem = &map->elems[key]; - - *prev = elem->freelist; - elem->in_use = true; - return elem; - } - } - return NULL; -} - -static struct lo_map_elem *lo_map_get(struct lo_map *map, size_t key) -{ - if (key >= map->nelems) { - return NULL; - } - if (!map->elems[key].in_use) { - return NULL; - } - return &map->elems[key]; -} - -static void lo_map_remove(struct lo_map *map, size_t key) -{ - struct lo_map_elem *elem; - - if (key >= map->nelems) { - return; - } - - elem = &map->elems[key]; - if (!elem->in_use) { - return; - } - - elem->in_use = false; - - elem->freelist = map->freelist; - map->freelist = key; -} - -/* Assumes lo->mutex is held */ -static ssize_t lo_add_fd_mapping(struct lo_data *lo, int fd) -{ - struct lo_map_elem *elem; - - elem = lo_map_alloc_elem(&lo->fd_map); - if (!elem) { - return -1; - } - - elem->fd = fd; - return elem - lo->fd_map.elems; -} - -/* Assumes lo->mutex is held */ -static ssize_t lo_add_dirp_mapping(fuse_req_t req, struct lo_dirp *dirp) -{ - struct lo_map_elem *elem; - - elem = lo_map_alloc_elem(&lo_data(req)->dirp_map); - if (!elem) { - return -1; - } - - elem->dirp = dirp; - return elem - lo_data(req)->dirp_map.elems; -} - -/* Assumes lo->mutex is held */ -static ssize_t lo_add_inode_mapping(fuse_req_t req, struct lo_inode *inode) -{ - struct lo_map_elem *elem; - - elem = lo_map_alloc_elem(&lo_data(req)->ino_map); - if (!elem) { - return -1; - } - - elem->inode = inode; - return elem - lo_data(req)->ino_map.elems; -} - -static void lo_inode_put(struct lo_data *lo, struct lo_inode **inodep) -{ - struct lo_inode *inode = *inodep; - - if (!inode) { - return; - } - - *inodep = NULL; - - if (g_atomic_int_dec_and_test(&inode->refcount)) { - close(inode->fd); - free(inode); - } -} - -/* Caller must release refcount using lo_inode_put() */ -static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino) -{ - struct lo_data *lo = lo_data(req); - struct lo_map_elem *elem; - - pthread_mutex_lock(&lo->mutex); - elem = lo_map_get(&lo->ino_map, ino); - if (elem) { - g_atomic_int_inc(&elem->inode->refcount); - } - pthread_mutex_unlock(&lo->mutex); - - if (!elem) { - return NULL; - } - - return elem->inode; -} - -/* - * TODO Remove this helper and force callers to hold an inode refcount until - * they are done with the fd. This will be done in a later patch to make - * review easier. - */ -static int lo_fd(fuse_req_t req, fuse_ino_t ino) -{ - struct lo_inode *inode = lo_inode(req, ino); - int fd; - - if (!inode) { - return -1; - } - - fd = inode->fd; - lo_inode_put(lo_data(req), &inode); - return fd; -} - -/* - * Open a file descriptor for an inode. Returns -EBADF if the inode is not a - * regular file or a directory. - * - * Use this helper function instead of raw openat(2) to prevent security issues - * when a malicious client opens special files such as block device nodes. - * Symlink inodes are also rejected since symlinks must already have been - * traversed on the client side. - */ -static int lo_inode_open(struct lo_data *lo, struct lo_inode *inode, - int open_flags) -{ - g_autofree char *fd_str = g_strdup_printf("%d", inode->fd); - int fd; - - if (!S_ISREG(inode->filetype) && !S_ISDIR(inode->filetype)) { - return -EBADF; - } - - /* - * The file is a symlink so O_NOFOLLOW must be ignored. We checked earlier - * that the inode is not a special file but if an external process races - * with us then symlinks are traversed here. It is not possible to escape - * the shared directory since it is mounted as "/" though. - */ - fd = openat(lo->proc_self_fd, fd_str, open_flags & ~O_NOFOLLOW); - if (fd < 0) { - return -errno; - } - return fd; -} - -static void lo_init(void *userdata, struct fuse_conn_info *conn) -{ - struct lo_data *lo = (struct lo_data *)userdata; - - if (conn->capable & FUSE_CAP_EXPORT_SUPPORT) { - conn->want |= FUSE_CAP_EXPORT_SUPPORT; - } - - if (lo->writeback && conn->capable & FUSE_CAP_WRITEBACK_CACHE) { - fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n"); - conn->want |= FUSE_CAP_WRITEBACK_CACHE; - } - if (conn->capable & FUSE_CAP_FLOCK_LOCKS) { - if (lo->flock) { - fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n"); - conn->want |= FUSE_CAP_FLOCK_LOCKS; - } else { - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling flock locks\n"); - conn->want &= ~FUSE_CAP_FLOCK_LOCKS; - } - } - - if (conn->capable & FUSE_CAP_POSIX_LOCKS) { - if (lo->posix_lock) { - fuse_log(FUSE_LOG_DEBUG, "lo_init: activating posix locks\n"); - conn->want |= FUSE_CAP_POSIX_LOCKS; - } else { - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling posix locks\n"); - conn->want &= ~FUSE_CAP_POSIX_LOCKS; - } - } - - if ((lo->cache == CACHE_NONE && !lo->readdirplus_set) || - lo->readdirplus_clear) { - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling readdirplus\n"); - conn->want &= ~FUSE_CAP_READDIRPLUS; - } - - if (!(conn->capable & FUSE_CAP_SUBMOUNTS) && lo->announce_submounts) { - fuse_log(FUSE_LOG_WARNING, "lo_init: Cannot announce submounts, client " - "does not support it\n"); - lo->announce_submounts = false; - } - - if (lo->user_killpriv_v2 == 1) { - /* - * User explicitly asked for this option. Enable it unconditionally. - * If connection does not have this capability, it should fail - * in fuse_lowlevel.c - */ - fuse_log(FUSE_LOG_DEBUG, "lo_init: enabling killpriv_v2\n"); - conn->want |= FUSE_CAP_HANDLE_KILLPRIV_V2; - lo->killpriv_v2 = 1; - } else { - /* - * Either user specified to disable killpriv_v2, or did not - * specify anything. Disable killpriv_v2 in both the cases. - */ - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling killpriv_v2\n"); - conn->want &= ~FUSE_CAP_HANDLE_KILLPRIV_V2; - lo->killpriv_v2 = 0; - } - - if (lo->user_posix_acl == 1) { - /* - * User explicitly asked for this option. Enable it unconditionally. - * If connection does not have this capability, print error message - * now. It will fail later in fuse_lowlevel.c - */ - if (!(conn->capable & FUSE_CAP_POSIX_ACL) || - !(conn->capable & FUSE_CAP_DONT_MASK) || - !(conn->capable & FUSE_CAP_SETXATTR_EXT)) { - fuse_log(FUSE_LOG_ERR, "lo_init: Can not enable posix acl." - " kernel does not support FUSE_POSIX_ACL, FUSE_DONT_MASK" - " or FUSE_SETXATTR_EXT capability.\n"); - } else { - fuse_log(FUSE_LOG_DEBUG, "lo_init: enabling posix acl\n"); - } - - conn->want |= FUSE_CAP_POSIX_ACL | FUSE_CAP_DONT_MASK | - FUSE_CAP_SETXATTR_EXT; - lo->change_umask = true; - lo->posix_acl = true; - } else { - /* User either did not specify anything or wants it disabled */ - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling posix_acl\n"); - conn->want &= ~FUSE_CAP_POSIX_ACL; - } - - if (lo->user_security_label == 1) { - if (!(conn->capable & FUSE_CAP_SECURITY_CTX)) { - fuse_log(FUSE_LOG_ERR, "lo_init: Can not enable security label." - " kernel does not support FUSE_SECURITY_CTX capability.\n"); - } - conn->want |= FUSE_CAP_SECURITY_CTX; - } else { - fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling security label\n"); - conn->want &= ~FUSE_CAP_SECURITY_CTX; - } -} - -static void lo_getattr(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - int res; - struct stat buf; - struct lo_data *lo = lo_data(req); - - (void)fi; - - res = - fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) { - return (void)fuse_reply_err(req, errno); - } - - fuse_reply_attr(req, &buf, lo->timeout); -} - -static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi) -{ - struct lo_data *lo = lo_data(req); - struct lo_map_elem *elem; - - pthread_mutex_lock(&lo->mutex); - elem = lo_map_get(&lo->fd_map, fi->fh); - pthread_mutex_unlock(&lo->mutex); - - if (!elem) { - return -1; - } - - return elem->fd; -} - -static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int valid, struct fuse_file_info *fi) -{ - int saverr; - char procname[64]; - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - int ifd; - int res; - int fd = -1; - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - ifd = inode->fd; - - /* If fi->fh is invalid we'll report EBADF later */ - if (fi) { - fd = lo_fi_fd(req, fi); - } - - if (valid & FUSE_SET_ATTR_MODE) { - if (fi) { - res = fchmod(fd, attr->st_mode); - } else { - sprintf(procname, "%i", ifd); - res = fchmodat(lo->proc_self_fd, procname, attr->st_mode, 0); - } - if (res == -1) { - saverr = errno; - goto out_err; - } - } - if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { - uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t)-1; - gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t)-1; - - saverr = drop_security_capability(lo, ifd); - if (saverr) { - goto out_err; - } - - res = fchownat(ifd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) { - saverr = errno; - goto out_err; - } - } - if (valid & FUSE_SET_ATTR_SIZE) { - int truncfd; - bool kill_suidgid; - bool cap_fsetid_dropped = false; - - kill_suidgid = lo->killpriv_v2 && (valid & FUSE_SET_ATTR_KILL_SUIDGID); - if (fi) { - truncfd = fd; - } else { - truncfd = lo_inode_open(lo, inode, O_RDWR); - if (truncfd < 0) { - saverr = -truncfd; - goto out_err; - } - } - - saverr = drop_security_capability(lo, truncfd); - if (saverr) { - if (!fi) { - close(truncfd); - } - goto out_err; - } - - if (kill_suidgid) { - res = drop_effective_cap("FSETID", &cap_fsetid_dropped); - if (res != 0) { - saverr = res; - if (!fi) { - close(truncfd); - } - goto out_err; - } - } - - res = ftruncate(truncfd, attr->st_size); - saverr = res == -1 ? errno : 0; - - if (cap_fsetid_dropped) { - if (gain_effective_cap("FSETID")) { - fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); - } - } - if (!fi) { - close(truncfd); - } - if (res == -1) { - goto out_err; - } - } - if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { - struct timespec tv[2]; - - tv[0].tv_sec = 0; - tv[1].tv_sec = 0; - tv[0].tv_nsec = UTIME_OMIT; - tv[1].tv_nsec = UTIME_OMIT; - - if (valid & FUSE_SET_ATTR_ATIME_NOW) { - tv[0].tv_nsec = UTIME_NOW; - } else if (valid & FUSE_SET_ATTR_ATIME) { - tv[0] = attr->st_atim; - } - - if (valid & FUSE_SET_ATTR_MTIME_NOW) { - tv[1].tv_nsec = UTIME_NOW; - } else if (valid & FUSE_SET_ATTR_MTIME) { - tv[1] = attr->st_mtim; - } - - if (fi) { - res = futimens(fd, tv); - } else { - sprintf(procname, "%i", inode->fd); - res = utimensat(lo->proc_self_fd, procname, tv, 0); - } - if (res == -1) { - saverr = errno; - goto out_err; - } - } - lo_inode_put(lo, &inode); - - return lo_getattr(req, ino, fi); - -out_err: - lo_inode_put(lo, &inode); - fuse_reply_err(req, saverr); -} - -static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st, - uint64_t mnt_id) -{ - struct lo_inode *p; - struct lo_key key = { - .ino = st->st_ino, - .dev = st->st_dev, - .mnt_id = mnt_id, - }; - - pthread_mutex_lock(&lo->mutex); - p = g_hash_table_lookup(lo->inodes, &key); - if (p) { - assert(p->nlookup > 0); - p->nlookup++; - g_atomic_int_inc(&p->refcount); - } - pthread_mutex_unlock(&lo->mutex); - - return p; -} - -/* value_destroy_func for posix_locks GHashTable */ -static void posix_locks_value_destroy(gpointer data) -{ - struct lo_inode_plock *plock = data; - - /* - * We had used open() for locks and had only one fd. So - * closing this fd should release all OFD locks. - */ - close(plock->fd); - free(plock); -} - -static int do_statx(struct lo_data *lo, int dirfd, const char *pathname, - struct stat *statbuf, int flags, uint64_t *mnt_id) -{ - int res; - -#if defined(CONFIG_STATX) && defined(CONFIG_STATX_MNT_ID) - if (lo->use_statx) { - struct statx statxbuf; - - res = statx(dirfd, pathname, flags, STATX_BASIC_STATS | STATX_MNT_ID, - &statxbuf); - if (!res) { - memset(statbuf, 0, sizeof(*statbuf)); - statbuf->st_dev = makedev(statxbuf.stx_dev_major, - statxbuf.stx_dev_minor); - statbuf->st_ino = statxbuf.stx_ino; - statbuf->st_mode = statxbuf.stx_mode; - statbuf->st_nlink = statxbuf.stx_nlink; - statbuf->st_uid = statxbuf.stx_uid; - statbuf->st_gid = statxbuf.stx_gid; - statbuf->st_rdev = makedev(statxbuf.stx_rdev_major, - statxbuf.stx_rdev_minor); - statbuf->st_size = statxbuf.stx_size; - statbuf->st_blksize = statxbuf.stx_blksize; - statbuf->st_blocks = statxbuf.stx_blocks; - statbuf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec; - statbuf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec; - statbuf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec; - statbuf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec; - statbuf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec; - statbuf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec; - - if (statxbuf.stx_mask & STATX_MNT_ID) { - *mnt_id = statxbuf.stx_mnt_id; - } else { - *mnt_id = 0; - } - return 0; - } else if (errno != ENOSYS) { - return -1; - } - lo->use_statx = false; - /* fallback */ - } -#endif - res = fstatat(dirfd, pathname, statbuf, flags); - if (res == -1) { - return -1; - } - *mnt_id = 0; - - return 0; -} - -/* - * Increments nlookup on the inode on success. unref_inode_lolocked() must be - * called eventually to decrement nlookup again. If inodep is non-NULL, the - * inode pointer is stored and the caller must call lo_inode_put(). - */ -static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, - struct fuse_entry_param *e, - struct lo_inode **inodep) -{ - int newfd; - int res; - int saverr; - uint64_t mnt_id; - struct lo_data *lo = lo_data(req); - struct lo_inode *inode = NULL; - struct lo_inode *dir = lo_inode(req, parent); - - if (inodep) { - *inodep = NULL; /* in case there is an error */ - } - - /* - * name_to_handle_at() and open_by_handle_at() can reach here with fuse - * mount point in guest, but we don't have its inode info in the - * ino_map. - */ - if (!dir) { - return ENOENT; - } - - memset(e, 0, sizeof(*e)); - e->attr_timeout = lo->timeout; - e->entry_timeout = lo->timeout; - - /* Do not allow escaping root directory */ - if (dir == &lo->root && strcmp(name, "..") == 0) { - name = "."; - } - - newfd = openat(dir->fd, name, O_PATH | O_NOFOLLOW); - if (newfd == -1) { - goto out_err; - } - - res = do_statx(lo, newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, - &mnt_id); - if (res == -1) { - goto out_err; - } - - if (S_ISDIR(e->attr.st_mode) && lo->announce_submounts && - (e->attr.st_dev != dir->key.dev || mnt_id != dir->key.mnt_id)) { - e->attr_flags |= FUSE_ATTR_SUBMOUNT; - } - - inode = lo_find(lo, &e->attr, mnt_id); - if (inode) { - close(newfd); - } else { - inode = calloc(1, sizeof(struct lo_inode)); - if (!inode) { - goto out_err; - } - - /* cache only filetype */ - inode->filetype = (e->attr.st_mode & S_IFMT); - - /* - * One for the caller and one for nlookup (released in - * unref_inode_lolocked()) - */ - g_atomic_int_set(&inode->refcount, 2); - - inode->nlookup = 1; - inode->fd = newfd; - inode->key.ino = e->attr.st_ino; - inode->key.dev = e->attr.st_dev; - inode->key.mnt_id = mnt_id; - if (lo->posix_lock) { - pthread_mutex_init(&inode->plock_mutex, NULL); - inode->posix_locks = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, posix_locks_value_destroy); - } - pthread_mutex_lock(&lo->mutex); - inode->fuse_ino = lo_add_inode_mapping(req, inode); - g_hash_table_insert(lo->inodes, &inode->key, inode); - pthread_mutex_unlock(&lo->mutex); - } - e->ino = inode->fuse_ino; - - /* Transfer ownership of inode pointer to caller or drop it */ - if (inodep) { - *inodep = inode; - } else { - lo_inode_put(lo, &inode); - } - - lo_inode_put(lo, &dir); - - fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long)parent, - name, (unsigned long long)e->ino); - - return 0; - -out_err: - saverr = errno; - if (newfd != -1) { - close(newfd); - } - lo_inode_put(lo, &inode); - lo_inode_put(lo, &dir); - return saverr; -} - -static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) -{ - struct fuse_entry_param e; - int err; - - fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n", parent, - name); - - if (is_empty(name)) { - fuse_reply_err(req, ENOENT); - return; - } - - /* - * Don't use is_safe_path_component(), allow "." and ".." for NFS export - * support. - */ - if (strchr(name, '/')) { - fuse_reply_err(req, EINVAL); - return; - } - - err = lo_do_lookup(req, parent, name, &e, NULL); - if (err) { - fuse_reply_err(req, err); - } else { - fuse_reply_entry(req, &e); - } -} - -/* - * On some archs, setres*id is limited to 2^16 but they - * provide setres*id32 variants that allow 2^32. - * Others just let setres*id do 2^32 anyway. - */ -#ifdef SYS_setresgid32 -#define OURSYS_setresgid SYS_setresgid32 -#else -#define OURSYS_setresgid SYS_setresgid -#endif - -#ifdef SYS_setresuid32 -#define OURSYS_setresuid SYS_setresuid32 -#else -#define OURSYS_setresuid SYS_setresuid -#endif - -static void drop_supplementary_groups(void) -{ - int ret; - - ret = getgroups(0, NULL); - if (ret == -1) { - fuse_log(FUSE_LOG_ERR, "getgroups() failed with error=%d:%s\n", - errno, strerror(errno)); - exit(1); - } - - if (!ret) { - return; - } - - /* Drop all supplementary groups. We should not need it */ - ret = setgroups(0, NULL); - if (ret == -1) { - fuse_log(FUSE_LOG_ERR, "setgroups() failed with error=%d:%s\n", - errno, strerror(errno)); - exit(1); - } -} - -/* - * Change to uid/gid of caller so that file is created with - * ownership of caller. - * TODO: What about selinux context? - */ -static int lo_change_cred(fuse_req_t req, struct lo_cred *old, - bool change_umask) -{ - int res; - - old->euid = geteuid(); - old->egid = getegid(); - - res = syscall(OURSYS_setresgid, -1, fuse_req_ctx(req)->gid, -1); - if (res == -1) { - return errno; - } - - res = syscall(OURSYS_setresuid, -1, fuse_req_ctx(req)->uid, -1); - if (res == -1) { - int errno_save = errno; - - syscall(OURSYS_setresgid, -1, old->egid, -1); - return errno_save; - } - - if (change_umask) { - old->umask = umask(req->ctx.umask); - } - return 0; -} - -/* Regain Privileges */ -static void lo_restore_cred(struct lo_cred *old, bool restore_umask) -{ - int res; - - res = syscall(OURSYS_setresuid, -1, old->euid, -1); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "seteuid(%u): %m\n", old->euid); - exit(1); - } - - res = syscall(OURSYS_setresgid, -1, old->egid, -1); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "setegid(%u): %m\n", old->egid); - exit(1); - } - - if (restore_umask) - umask(old->umask); -} - -/* - * A helper to change cred and drop capability. Returns 0 on success and - * errno on error - */ -static int lo_drop_cap_change_cred(fuse_req_t req, struct lo_cred *old, - bool change_umask, const char *cap_name, - bool *cap_dropped) -{ - int ret; - bool __cap_dropped; - - assert(cap_name); - - ret = drop_effective_cap(cap_name, &__cap_dropped); - if (ret) { - return ret; - } - - ret = lo_change_cred(req, old, change_umask); - if (ret) { - if (__cap_dropped) { - if (gain_effective_cap(cap_name)) { - fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_%s\n", cap_name); - } - } - } - - if (cap_dropped) { - *cap_dropped = __cap_dropped; - } - return ret; -} - -static void lo_restore_cred_gain_cap(struct lo_cred *old, bool restore_umask, - const char *cap_name) -{ - assert(cap_name); - - lo_restore_cred(old, restore_umask); - - if (gain_effective_cap(cap_name)) { - fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_%s\n", cap_name); - } -} - -static int do_mknod_symlink_secctx(fuse_req_t req, struct lo_inode *dir, - const char *name, const char *secctx_name) -{ - int path_fd, err; - char procname[64]; - struct lo_data *lo = lo_data(req); - - if (!req->secctx.ctxlen) { - return 0; - } - - /* Open newly created element with O_PATH */ - path_fd = openat(dir->fd, name, O_PATH | O_NOFOLLOW); - err = path_fd == -1 ? errno : 0; - if (err) { - return err; - } - sprintf(procname, "%i", path_fd); - FCHDIR_NOFAIL(lo->proc_self_fd); - /* Set security context. This is not atomic w.r.t file creation */ - err = setxattr(procname, secctx_name, req->secctx.ctx, req->secctx.ctxlen, - 0); - if (err) { - err = errno; - } - FCHDIR_NOFAIL(lo->root.fd); - close(path_fd); - return err; -} - -static int do_mknod_symlink(fuse_req_t req, struct lo_inode *dir, - const char *name, mode_t mode, dev_t rdev, - const char *link) -{ - int err, fscreate_fd = -1; - const char *secctx_name = req->secctx.name; - struct lo_cred old = {}; - struct lo_data *lo = lo_data(req); - char *mapped_name = NULL; - bool secctx_enabled = req->secctx.ctxlen; - bool do_fscreate = false; - - if (secctx_enabled && lo->xattrmap) { - err = xattr_map_client(lo, req->secctx.name, &mapped_name); - if (err < 0) { - return -err; - } - secctx_name = mapped_name; - } - - /* - * If security xattr has not been remapped and selinux is enabled on - * host, set fscreate and no need to do a setxattr() after file creation - */ - if (secctx_enabled && !mapped_name && lo->use_fscreate) { - do_fscreate = true; - err = open_set_proc_fscreate(lo, req->secctx.ctx, req->secctx.ctxlen, - &fscreate_fd); - if (err) { - goto out; - } - } - - err = lo_change_cred(req, &old, lo->change_umask && !S_ISLNK(mode)); - if (err) { - goto out; - } - - err = mknod_wrapper(dir->fd, name, link, mode, rdev); - err = err == -1 ? errno : 0; - lo_restore_cred(&old, lo->change_umask && !S_ISLNK(mode)); - if (err) { - goto out; - } - - if (!do_fscreate) { - err = do_mknod_symlink_secctx(req, dir, name, secctx_name); - if (err) { - unlinkat(dir->fd, name, S_ISDIR(mode) ? AT_REMOVEDIR : 0); - } - } -out: - if (fscreate_fd != -1) { - close_reset_proc_fscreate(fscreate_fd); - } - g_free(mapped_name); - return err; -} - -static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent, - const char *name, mode_t mode, dev_t rdev, - const char *link) -{ - int saverr; - struct lo_data *lo = lo_data(req); - struct lo_inode *dir; - struct fuse_entry_param e; - - if (is_empty(name)) { - fuse_reply_err(req, ENOENT); - return; - } - - if (!is_safe_path_component(name)) { - fuse_reply_err(req, EINVAL); - return; - } - - dir = lo_inode(req, parent); - if (!dir) { - fuse_reply_err(req, EBADF); - return; - } - - saverr = do_mknod_symlink(req, dir, name, mode, rdev, link); - if (saverr) { - goto out; - } - - saverr = lo_do_lookup(req, parent, name, &e, NULL); - if (saverr) { - goto out; - } - - fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long)parent, - name, (unsigned long long)e.ino); - - fuse_reply_entry(req, &e); - lo_inode_put(lo, &dir); - return; - -out: - lo_inode_put(lo, &dir); - fuse_reply_err(req, saverr); -} - -static void lo_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev) -{ - lo_mknod_symlink(req, parent, name, mode, rdev, NULL); -} - -static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode) -{ - lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL); -} - -static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name) -{ - lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link); -} - -static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, - const char *name) -{ - int res; - struct lo_data *lo = lo_data(req); - struct lo_inode *parent_inode; - struct lo_inode *inode; - struct fuse_entry_param e; - char procname[64]; - int saverr; - - if (is_empty(name)) { - fuse_reply_err(req, ENOENT); - return; - } - - if (!is_safe_path_component(name)) { - fuse_reply_err(req, EINVAL); - return; - } - - parent_inode = lo_inode(req, parent); - inode = lo_inode(req, ino); - if (!parent_inode || !inode) { - errno = EBADF; - goto out_err; - } - - memset(&e, 0, sizeof(struct fuse_entry_param)); - e.attr_timeout = lo->timeout; - e.entry_timeout = lo->timeout; - - sprintf(procname, "%i", inode->fd); - res = linkat(lo->proc_self_fd, procname, parent_inode->fd, name, - AT_SYMLINK_FOLLOW); - if (res == -1) { - goto out_err; - } - - res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) { - goto out_err; - } - - pthread_mutex_lock(&lo->mutex); - inode->nlookup++; - pthread_mutex_unlock(&lo->mutex); - e.ino = inode->fuse_ino; - - fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long)parent, - name, (unsigned long long)e.ino); - - fuse_reply_entry(req, &e); - lo_inode_put(lo, &parent_inode); - lo_inode_put(lo, &inode); - return; - -out_err: - saverr = errno; - lo_inode_put(lo, &parent_inode); - lo_inode_put(lo, &inode); - fuse_reply_err(req, saverr); -} - -/* Increments nlookup and caller must release refcount using lo_inode_put() */ -static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent, - const char *name) -{ - int res; - uint64_t mnt_id; - struct stat attr; - struct lo_data *lo = lo_data(req); - struct lo_inode *dir = lo_inode(req, parent); - - if (!dir) { - return NULL; - } - - res = do_statx(lo, dir->fd, name, &attr, AT_SYMLINK_NOFOLLOW, &mnt_id); - lo_inode_put(lo, &dir); - if (res == -1) { - return NULL; - } - - return lo_find(lo, &attr, mnt_id); -} - -static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) -{ - int res; - struct lo_inode *inode; - struct lo_data *lo = lo_data(req); - - if (is_empty(name)) { - fuse_reply_err(req, ENOENT); - return; - } - - if (!is_safe_path_component(name)) { - fuse_reply_err(req, EINVAL); - return; - } - - inode = lookup_name(req, parent, name); - if (!inode) { - fuse_reply_err(req, EIO); - return; - } - - res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR); - - fuse_reply_err(req, res == -1 ? errno : 0); - unref_inode_lolocked(lo, inode, 1); - lo_inode_put(lo, &inode); -} - -static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname, - unsigned int flags) -{ - int res; - struct lo_inode *parent_inode; - struct lo_inode *newparent_inode; - struct lo_inode *oldinode = NULL; - struct lo_inode *newinode = NULL; - struct lo_data *lo = lo_data(req); - - if (is_empty(name) || is_empty(newname)) { - fuse_reply_err(req, ENOENT); - return; - } - - if (!is_safe_path_component(name) || !is_safe_path_component(newname)) { - fuse_reply_err(req, EINVAL); - return; - } - - parent_inode = lo_inode(req, parent); - newparent_inode = lo_inode(req, newparent); - if (!parent_inode || !newparent_inode) { - fuse_reply_err(req, EBADF); - goto out; - } - - oldinode = lookup_name(req, parent, name); - newinode = lookup_name(req, newparent, newname); - - if (!oldinode) { - fuse_reply_err(req, EIO); - goto out; - } - - if (flags) { -#ifndef SYS_renameat2 - fuse_reply_err(req, EINVAL); -#else - res = syscall(SYS_renameat2, parent_inode->fd, name, - newparent_inode->fd, newname, flags); - if (res == -1 && errno == ENOSYS) { - fuse_reply_err(req, EINVAL); - } else { - fuse_reply_err(req, res == -1 ? errno : 0); - } -#endif - goto out; - } - - res = renameat(parent_inode->fd, name, newparent_inode->fd, newname); - - fuse_reply_err(req, res == -1 ? errno : 0); -out: - unref_inode_lolocked(lo, oldinode, 1); - unref_inode_lolocked(lo, newinode, 1); - lo_inode_put(lo, &oldinode); - lo_inode_put(lo, &newinode); - lo_inode_put(lo, &parent_inode); - lo_inode_put(lo, &newparent_inode); -} - -static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) -{ - int res; - struct lo_inode *inode; - struct lo_data *lo = lo_data(req); - - if (is_empty(name)) { - fuse_reply_err(req, ENOENT); - return; - } - - if (!is_safe_path_component(name)) { - fuse_reply_err(req, EINVAL); - return; - } - - inode = lookup_name(req, parent, name); - if (!inode) { - fuse_reply_err(req, EIO); - return; - } - - res = unlinkat(lo_fd(req, parent), name, 0); - - fuse_reply_err(req, res == -1 ? errno : 0); - unref_inode_lolocked(lo, inode, 1); - lo_inode_put(lo, &inode); -} - -/* To be called with lo->mutex held */ -static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n) -{ - if (!inode) { - return; - } - - assert(inode->nlookup >= n); - inode->nlookup -= n; - if (!inode->nlookup) { - lo_map_remove(&lo->ino_map, inode->fuse_ino); - g_hash_table_remove(lo->inodes, &inode->key); - if (lo->posix_lock) { - if (g_hash_table_size(inode->posix_locks)) { - fuse_log(FUSE_LOG_WARNING, "Hash table is not empty\n"); - } - g_hash_table_destroy(inode->posix_locks); - pthread_mutex_destroy(&inode->plock_mutex); - } - /* Drop our refcount from lo_do_lookup() */ - lo_inode_put(lo, &inode); - } -} - -static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode, - uint64_t n) -{ - if (!inode) { - return; - } - - pthread_mutex_lock(&lo->mutex); - unref_inode(lo, inode, n); - pthread_mutex_unlock(&lo->mutex); -} - -static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) -{ - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - - inode = lo_inode(req, ino); - if (!inode) { - return; - } - - fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n", - (unsigned long long)ino, (unsigned long long)inode->nlookup, - (unsigned long long)nlookup); - - unref_inode_lolocked(lo, inode, nlookup); - lo_inode_put(lo, &inode); -} - -static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) -{ - lo_forget_one(req, ino, nlookup); - fuse_reply_none(req); -} - -static void lo_forget_multi(fuse_req_t req, size_t count, - struct fuse_forget_data *forgets) -{ - int i; - - for (i = 0; i < count; i++) { - lo_forget_one(req, forgets[i].ino, forgets[i].nlookup); - } - fuse_reply_none(req); -} - -static void lo_readlink(fuse_req_t req, fuse_ino_t ino) -{ - char buf[PATH_MAX + 1]; - int res; - - res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf)); - if (res == -1) { - return (void)fuse_reply_err(req, errno); - } - - if (res == sizeof(buf)) { - return (void)fuse_reply_err(req, ENAMETOOLONG); - } - - buf[res] = '\0'; - - fuse_reply_readlink(req, buf); -} - -struct lo_dirp { - gint refcount; - DIR *dp; - struct dirent *entry; - off_t offset; -}; - -static void lo_dirp_put(struct lo_dirp **dp) -{ - struct lo_dirp *d = *dp; - - if (!d) { - return; - } - *dp = NULL; - - if (g_atomic_int_dec_and_test(&d->refcount)) { - closedir(d->dp); - free(d); - } -} - -/* Call lo_dirp_put() on the return value when no longer needed */ -static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi) -{ - struct lo_data *lo = lo_data(req); - struct lo_map_elem *elem; - - pthread_mutex_lock(&lo->mutex); - elem = lo_map_get(&lo->dirp_map, fi->fh); - if (elem) { - g_atomic_int_inc(&elem->dirp->refcount); - } - pthread_mutex_unlock(&lo->mutex); - if (!elem) { - return NULL; - } - - return elem->dirp; -} - -static void lo_opendir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - int error = ENOMEM; - struct lo_data *lo = lo_data(req); - struct lo_dirp *d; - int fd; - ssize_t fh; - - d = calloc(1, sizeof(struct lo_dirp)); - if (d == NULL) { - goto out_err; - } - - fd = openat(lo_fd(req, ino), ".", O_RDONLY); - if (fd == -1) { - goto out_errno; - } - - d->dp = fdopendir(fd); - if (d->dp == NULL) { - goto out_errno; - } - - d->offset = 0; - d->entry = NULL; - - g_atomic_int_set(&d->refcount, 1); /* paired with lo_releasedir() */ - pthread_mutex_lock(&lo->mutex); - fh = lo_add_dirp_mapping(req, d); - pthread_mutex_unlock(&lo->mutex); - if (fh == -1) { - goto out_err; - } - - fi->fh = fh; - if (lo->cache == CACHE_ALWAYS) { - fi->cache_readdir = 1; - } - fuse_reply_open(req, fi); - return; - -out_errno: - error = errno; -out_err: - if (d) { - if (d->dp) { - closedir(d->dp); - } else if (fd != -1) { - close(fd); - } - free(d); - } - fuse_reply_err(req, error); -} - -static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi, int plus) -{ - struct lo_data *lo = lo_data(req); - struct lo_dirp *d = NULL; - struct lo_inode *dinode; - g_autofree char *buf = NULL; - char *p; - size_t rem = size; - int err = EBADF; - - dinode = lo_inode(req, ino); - if (!dinode) { - goto error; - } - - d = lo_dirp(req, fi); - if (!d) { - goto error; - } - - err = ENOMEM; - buf = g_try_malloc0(size); - if (!buf) { - goto error; - } - p = buf; - - if (offset != d->offset) { - seekdir(d->dp, offset); - d->entry = NULL; - d->offset = offset; - } - while (1) { - size_t entsize; - off_t nextoff; - const char *name; - - if (!d->entry) { - errno = 0; - d->entry = readdir(d->dp); - if (!d->entry) { - if (errno) { /* Error */ - err = errno; - goto error; - } else { /* End of stream */ - break; - } - } - } - nextoff = d->entry->d_off; - name = d->entry->d_name; - - fuse_ino_t entry_ino = 0; - struct fuse_entry_param e = (struct fuse_entry_param){ - .attr.st_ino = d->entry->d_ino, - .attr.st_mode = d->entry->d_type << 12, - }; - - /* Hide root's parent directory */ - if (dinode == &lo->root && strcmp(name, "..") == 0) { - e.attr.st_ino = lo->root.key.ino; - e.attr.st_mode = DT_DIR << 12; - } - - if (plus) { - if (!is_dot_or_dotdot(name)) { - err = lo_do_lookup(req, ino, name, &e, NULL); - if (err) { - goto error; - } - entry_ino = e.ino; - } - - entsize = fuse_add_direntry_plus(req, p, rem, name, &e, nextoff); - } else { - entsize = fuse_add_direntry(req, p, rem, name, &e.attr, nextoff); - } - if (entsize > rem) { - if (entry_ino != 0) { - lo_forget_one(req, entry_ino, 1); - } - break; - } - - p += entsize; - rem -= entsize; - - d->entry = NULL; - d->offset = nextoff; - } - - err = 0; -error: - lo_dirp_put(&d); - lo_inode_put(lo, &dinode); - - /* - * If there's an error, we can only signal it if we haven't stored - * any entries yet - otherwise we'd end up with wrong lookup - * counts for the entries that are already in the buffer. So we - * return what we've collected until that point. - */ - if (err && rem == size) { - fuse_reply_err(req, err); - } else { - fuse_reply_buf(req, buf, size - rem); - } -} - -static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - lo_do_readdir(req, ino, size, offset, fi, 0); -} - -static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - lo_do_readdir(req, ino, size, offset, fi, 1); -} - -static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct lo_data *lo = lo_data(req); - struct lo_map_elem *elem; - struct lo_dirp *d; - - (void)ino; - - pthread_mutex_lock(&lo->mutex); - elem = lo_map_get(&lo->dirp_map, fi->fh); - if (!elem) { - pthread_mutex_unlock(&lo->mutex); - fuse_reply_err(req, EBADF); - return; - } - - d = elem->dirp; - lo_map_remove(&lo->dirp_map, fi->fh); - pthread_mutex_unlock(&lo->mutex); - - lo_dirp_put(&d); /* paired with lo_opendir() */ - - fuse_reply_err(req, 0); -} - -static void update_open_flags(int writeback, int allow_direct_io, - struct fuse_file_info *fi) -{ - /* - * With writeback cache, kernel may send read requests even - * when userspace opened write-only - */ - if (writeback && (fi->flags & O_ACCMODE) == O_WRONLY) { - fi->flags &= ~O_ACCMODE; - fi->flags |= O_RDWR; - } - - /* - * With writeback cache, O_APPEND is handled by the kernel. - * This breaks atomicity (since the file may change in the - * underlying filesystem, so that the kernel's idea of the - * end of the file isn't accurate anymore). In this example, - * we just accept that. A more rigorous filesystem may want - * to return an error here - */ - if (writeback && (fi->flags & O_APPEND)) { - fi->flags &= ~O_APPEND; - } - - /* - * O_DIRECT in guest should not necessarily mean bypassing page - * cache on host as well. Therefore, we discard it by default - * ('-o no_allow_direct_io'). If somebody needs that behavior, - * the '-o allow_direct_io' option should be set. - */ - if (!allow_direct_io) { - fi->flags &= ~O_DIRECT; - } -} - -/* - * Open a regular file, set up an fd mapping, and fill out the struct - * fuse_file_info for it. If existing_fd is not negative, use that fd instead - * opening a new one. Takes ownership of existing_fd. - * - * Returns 0 on success or a positive errno. - */ -static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, - int existing_fd, struct fuse_file_info *fi) -{ - ssize_t fh; - int fd = existing_fd; - int err; - bool cap_fsetid_dropped = false; - bool kill_suidgid = lo->killpriv_v2 && fi->kill_priv; - - update_open_flags(lo->writeback, lo->allow_direct_io, fi); - - if (fd < 0) { - if (kill_suidgid) { - err = drop_effective_cap("FSETID", &cap_fsetid_dropped); - if (err) { - return err; - } - } - - fd = lo_inode_open(lo, inode, fi->flags); - - if (cap_fsetid_dropped) { - if (gain_effective_cap("FSETID")) { - fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); - } - } - if (fd < 0) { - return -fd; - } - if (fi->flags & (O_TRUNC)) { - int err = drop_security_capability(lo, fd); - if (err) { - close(fd); - return err; - } - } - } - - pthread_mutex_lock(&lo->mutex); - fh = lo_add_fd_mapping(lo, fd); - pthread_mutex_unlock(&lo->mutex); - if (fh == -1) { - close(fd); - return ENOMEM; - } - - fi->fh = fh; - if (lo->cache == CACHE_NONE) { - fi->direct_io = 1; - } else if (lo->cache == CACHE_ALWAYS) { - fi->keep_cache = 1; - } - return 0; -} - -static int do_create_nosecctx(fuse_req_t req, struct lo_inode *parent_inode, - const char *name, mode_t mode, - struct fuse_file_info *fi, int *open_fd, - bool tmpfile) -{ - int err, fd; - struct lo_cred old = {}; - struct lo_data *lo = lo_data(req); - int flags; - - if (tmpfile) { - flags = fi->flags | O_TMPFILE; - /* - * Don't use O_EXCL as we want to link file later. Also reset O_CREAT - * otherwise openat() returns -EINVAL. - */ - flags &= ~(O_CREAT | O_EXCL); - - /* O_TMPFILE needs either O_RDWR or O_WRONLY */ - if ((flags & O_ACCMODE) == O_RDONLY) { - flags |= O_RDWR; - } - } else { - flags = fi->flags | O_CREAT | O_EXCL; - } - - err = lo_change_cred(req, &old, lo->change_umask); - if (err) { - return err; - } - - /* Try to create a new file but don't open existing files */ - fd = openat(parent_inode->fd, name, flags, mode); - err = fd == -1 ? errno : 0; - lo_restore_cred(&old, lo->change_umask); - if (!err) { - *open_fd = fd; - } - return err; -} - -static int do_create_secctx_fscreate(fuse_req_t req, - struct lo_inode *parent_inode, - const char *name, mode_t mode, - struct fuse_file_info *fi, int *open_fd) -{ - int err = 0, fd = -1, fscreate_fd = -1; - struct lo_data *lo = lo_data(req); - - err = open_set_proc_fscreate(lo, req->secctx.ctx, req->secctx.ctxlen, - &fscreate_fd); - if (err) { - return err; - } - - err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false); - - close_reset_proc_fscreate(fscreate_fd); - if (!err) { - *open_fd = fd; - } - return err; -} - -static int do_create_secctx_tmpfile(fuse_req_t req, - struct lo_inode *parent_inode, - const char *name, mode_t mode, - struct fuse_file_info *fi, - const char *secctx_name, int *open_fd) -{ - int err, fd = -1; - struct lo_data *lo = lo_data(req); - char procname[64]; - - err = do_create_nosecctx(req, parent_inode, ".", mode, fi, &fd, true); - if (err) { - return err; - } - - err = fsetxattr(fd, secctx_name, req->secctx.ctx, req->secctx.ctxlen, 0); - if (err) { - err = errno; - goto out; - } - - /* Security context set on file. Link it in place */ - sprintf(procname, "%d", fd); - FCHDIR_NOFAIL(lo->proc_self_fd); - err = linkat(AT_FDCWD, procname, parent_inode->fd, name, - AT_SYMLINK_FOLLOW); - err = err == -1 ? errno : 0; - FCHDIR_NOFAIL(lo->root.fd); - -out: - if (!err) { - *open_fd = fd; - } else if (fd != -1) { - close(fd); - } - return err; -} - -static int do_create_secctx_noatomic(fuse_req_t req, - struct lo_inode *parent_inode, - const char *name, mode_t mode, - struct fuse_file_info *fi, - const char *secctx_name, int *open_fd) -{ - int err = 0, fd = -1; - - err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false); - if (err) { - goto out; - } - - /* Set security context. This is not atomic w.r.t file creation */ - err = fsetxattr(fd, secctx_name, req->secctx.ctx, req->secctx.ctxlen, 0); - err = err == -1 ? errno : 0; -out: - if (!err) { - *open_fd = fd; - } else { - if (fd != -1) { - close(fd); - unlinkat(parent_inode->fd, name, 0); - } - } - return err; -} - -static int do_lo_create(fuse_req_t req, struct lo_inode *parent_inode, - const char *name, mode_t mode, - struct fuse_file_info *fi, int *open_fd) -{ - struct lo_data *lo = lo_data(req); - char *mapped_name = NULL; - int err; - const char *ctxname = req->secctx.name; - bool secctx_enabled = req->secctx.ctxlen; - - if (secctx_enabled && lo->xattrmap) { - err = xattr_map_client(lo, req->secctx.name, &mapped_name); - if (err < 0) { - return -err; - } - - ctxname = mapped_name; - } - - if (secctx_enabled) { - /* - * If security.selinux has not been remapped and selinux is enabled, - * use fscreate to set context before file creation. If not, use - * tmpfile method for regular files. Otherwise fallback to - * non-atomic method of file creation and xattr setting. - */ - if (!mapped_name && lo->use_fscreate) { - err = do_create_secctx_fscreate(req, parent_inode, name, mode, fi, - open_fd); - goto out; - } else if (S_ISREG(mode)) { - err = do_create_secctx_tmpfile(req, parent_inode, name, mode, fi, - ctxname, open_fd); - /* - * If filesystem does not support O_TMPFILE, fallback to non-atomic - * method. - */ - if (!err || err != EOPNOTSUPP) { - goto out; - } - } - - err = do_create_secctx_noatomic(req, parent_inode, name, mode, fi, - ctxname, open_fd); - } else { - err = do_create_nosecctx(req, parent_inode, name, mode, fi, open_fd, - false); - } - -out: - g_free(mapped_name); - return err; -} - -static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi) -{ - int fd = -1; - struct lo_data *lo = lo_data(req); - struct lo_inode *parent_inode; - struct lo_inode *inode = NULL; - struct fuse_entry_param e; - int err; - - fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)" - " kill_priv=%d\n", parent, name, fi->kill_priv); - - if (!is_safe_path_component(name)) { - fuse_reply_err(req, EINVAL); - return; - } - - parent_inode = lo_inode(req, parent); - if (!parent_inode) { - fuse_reply_err(req, EBADF); - return; - } - - update_open_flags(lo->writeback, lo->allow_direct_io, fi); - - err = do_lo_create(req, parent_inode, name, mode, fi, &fd); - - /* Ignore the error if file exists and O_EXCL was not given */ - if (err && (err != EEXIST || (fi->flags & O_EXCL))) { - goto out; - } - - err = lo_do_lookup(req, parent, name, &e, &inode); - if (err) { - goto out; - } - - err = lo_do_open(lo, inode, fd, fi); - fd = -1; /* lo_do_open() takes ownership of fd */ - if (err) { - /* Undo lo_do_lookup() nlookup ref */ - unref_inode_lolocked(lo, inode, 1); - } - -out: - lo_inode_put(lo, &inode); - lo_inode_put(lo, &parent_inode); - - if (err) { - if (fd >= 0) { - close(fd); - } - - fuse_reply_err(req, err); - } else { - fuse_reply_create(req, &e, fi); - } -} - -/* Should be called with inode->plock_mutex held */ -static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo, - struct lo_inode *inode, - uint64_t lock_owner, - pid_t pid, int *err) -{ - struct lo_inode_plock *plock; - int fd; - - plock = - g_hash_table_lookup(inode->posix_locks, GUINT_TO_POINTER(lock_owner)); - - if (plock) { - return plock; - } - - plock = malloc(sizeof(struct lo_inode_plock)); - if (!plock) { - *err = ENOMEM; - return NULL; - } - - /* Open another instance of file which can be used for ofd locks. */ - /* TODO: What if file is not writable? */ - fd = lo_inode_open(lo, inode, O_RDWR); - if (fd < 0) { - *err = -fd; - free(plock); - return NULL; - } - - plock->lock_owner = lock_owner; - plock->fd = fd; - g_hash_table_insert(inode->posix_locks, GUINT_TO_POINTER(plock->lock_owner), - plock); - return plock; -} - -static void lo_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock) -{ - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - struct lo_inode_plock *plock; - int ret, saverr = 0; - - fuse_log(FUSE_LOG_DEBUG, - "lo_getlk(ino=%" PRIu64 ", flags=%d)" - " owner=0x%" PRIx64 ", l_type=%d l_start=0x%" PRIx64 - " l_len=0x%" PRIx64 "\n", - ino, fi->flags, fi->lock_owner, lock->l_type, - (uint64_t)lock->l_start, (uint64_t)lock->l_len); - - if (!lo->posix_lock) { - fuse_reply_err(req, ENOSYS); - return; - } - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - pthread_mutex_lock(&inode->plock_mutex); - plock = - lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret); - if (!plock) { - saverr = ret; - goto out; - } - - ret = fcntl(plock->fd, F_OFD_GETLK, lock); - if (ret == -1) { - saverr = errno; - } - -out: - pthread_mutex_unlock(&inode->plock_mutex); - lo_inode_put(lo, &inode); - - if (saverr) { - fuse_reply_err(req, saverr); - } else { - fuse_reply_lock(req, lock); - } -} - -static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock, int sleep) -{ - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - struct lo_inode_plock *plock; - int ret, saverr = 0; - - fuse_log(FUSE_LOG_DEBUG, - "lo_setlk(ino=%" PRIu64 ", flags=%d)" - " cmd=%d pid=%d owner=0x%" PRIx64 " sleep=%d l_whence=%d" - " l_start=0x%" PRIx64 " l_len=0x%" PRIx64 "\n", - ino, fi->flags, lock->l_type, lock->l_pid, fi->lock_owner, sleep, - lock->l_whence, (uint64_t)lock->l_start, (uint64_t)lock->l_len); - - if (!lo->posix_lock) { - fuse_reply_err(req, ENOSYS); - return; - } - - if (sleep) { - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - pthread_mutex_lock(&inode->plock_mutex); - plock = - lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret); - - if (!plock) { - saverr = ret; - goto out; - } - - /* TODO: Is it alright to modify flock? */ - lock->l_pid = 0; - ret = fcntl(plock->fd, F_OFD_SETLK, lock); - if (ret == -1) { - saverr = errno; - } - -out: - pthread_mutex_unlock(&inode->plock_mutex); - lo_inode_put(lo, &inode); - - fuse_reply_err(req, saverr); -} - -static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) -{ - int res; - struct lo_dirp *d; - int fd; - - (void)ino; - - d = lo_dirp(req, fi); - if (!d) { - fuse_reply_err(req, EBADF); - return; - } - - fd = dirfd(d->dp); - if (datasync) { - res = fdatasync(fd); - } else { - res = fsync(fd); - } - - lo_dirp_put(&d); - - fuse_reply_err(req, res == -1 ? errno : 0); -} - -static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) -{ - struct lo_data *lo = lo_data(req); - struct lo_inode *inode = lo_inode(req, ino); - int err; - - fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d, kill_priv=%d)" - "\n", ino, fi->flags, fi->kill_priv); - - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - err = lo_do_open(lo, inode, -1, fi); - lo_inode_put(lo, &inode); - if (err) { - fuse_reply_err(req, err); - } else { - fuse_reply_open(req, fi); - } -} - -static void lo_release(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct lo_data *lo = lo_data(req); - struct lo_map_elem *elem; - int fd = -1; - - (void)ino; - - pthread_mutex_lock(&lo->mutex); - elem = lo_map_get(&lo->fd_map, fi->fh); - if (elem) { - fd = elem->fd; - elem = NULL; - lo_map_remove(&lo->fd_map, fi->fh); - } - pthread_mutex_unlock(&lo->mutex); - - close(fd); - fuse_reply_err(req, 0); -} - -static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) -{ - int res; - (void)ino; - struct lo_inode *inode; - struct lo_data *lo = lo_data(req); - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - if (!S_ISREG(inode->filetype)) { - lo_inode_put(lo, &inode); - fuse_reply_err(req, EBADF); - return; - } - - /* An fd is going away. Cleanup associated posix locks */ - if (lo->posix_lock) { - pthread_mutex_lock(&inode->plock_mutex); - g_hash_table_remove(inode->posix_locks, - GUINT_TO_POINTER(fi->lock_owner)); - pthread_mutex_unlock(&inode->plock_mutex); - } - res = close(dup(lo_fi_fd(req, fi))); - lo_inode_put(lo, &inode); - fuse_reply_err(req, res == -1 ? errno : 0); -} - -static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) -{ - struct lo_inode *inode = lo_inode(req, ino); - struct lo_data *lo = lo_data(req); - int res; - int fd; - - fuse_log(FUSE_LOG_DEBUG, "lo_fsync(ino=%" PRIu64 ", fi=0x%p)\n", ino, - (void *)fi); - - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - if (!fi) { - fd = lo_inode_open(lo, inode, O_RDWR); - if (fd < 0) { - res = -fd; - goto out; - } - } else { - fd = lo_fi_fd(req, fi); - } - - if (datasync) { - res = fdatasync(fd) == -1 ? errno : 0; - } else { - res = fsync(fd) == -1 ? errno : 0; - } - if (!fi) { - close(fd); - } -out: - lo_inode_put(lo, &inode); - fuse_reply_err(req, res); -} - -static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, - struct fuse_file_info *fi) -{ - struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size); - - fuse_log(FUSE_LOG_DEBUG, - "lo_read(ino=%" PRIu64 ", size=%zd, " - "off=%lu)\n", - ino, size, (unsigned long)offset); - - buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; - buf.buf[0].fd = lo_fi_fd(req, fi); - buf.buf[0].pos = offset; - - fuse_reply_data(req, &buf); -} - -static void lo_write_buf(fuse_req_t req, fuse_ino_t ino, - struct fuse_bufvec *in_buf, off_t off, - struct fuse_file_info *fi) -{ - (void)ino; - ssize_t res; - struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf)); - bool cap_fsetid_dropped = false; - - out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; - out_buf.buf[0].fd = lo_fi_fd(req, fi); - out_buf.buf[0].pos = off; - - fuse_log(FUSE_LOG_DEBUG, - "lo_write_buf(ino=%" PRIu64 ", size=%zd, off=%lu kill_priv=%d)\n", - ino, out_buf.buf[0].size, (unsigned long)off, fi->kill_priv); - - res = drop_security_capability(lo_data(req), out_buf.buf[0].fd); - if (res) { - fuse_reply_err(req, res); - return; - } - - /* - * If kill_priv is set, drop CAP_FSETID which should lead to kernel - * clearing setuid/setgid on file. Note, for WRITE, we need to do - * this even if killpriv_v2 is not enabled. fuse direct write path - * relies on this. - */ - if (fi->kill_priv) { - res = drop_effective_cap("FSETID", &cap_fsetid_dropped); - if (res != 0) { - fuse_reply_err(req, res); - return; - } - } - - res = fuse_buf_copy(&out_buf, in_buf); - if (res < 0) { - fuse_reply_err(req, -res); - } else { - fuse_reply_write(req, (size_t)res); - } - - if (cap_fsetid_dropped) { - res = gain_effective_cap("FSETID"); - if (res) { - fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n"); - } - } -} - -static void lo_statfs(fuse_req_t req, fuse_ino_t ino) -{ - int res; - struct statvfs stbuf; - - res = fstatvfs(lo_fd(req, ino), &stbuf); - if (res == -1) { - fuse_reply_err(req, errno); - } else { - fuse_reply_statfs(req, &stbuf); - } -} - -static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, - off_t length, struct fuse_file_info *fi) -{ - int err = EOPNOTSUPP; - (void)ino; - -#ifdef CONFIG_FALLOCATE - err = fallocate(lo_fi_fd(req, fi), mode, offset, length); - if (err < 0) { - err = errno; - } - -#elif defined(CONFIG_POSIX_FALLOCATE) - if (mode) { - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - err = posix_fallocate(lo_fi_fd(req, fi), offset, length); -#endif - - fuse_reply_err(req, err); -} - -static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - int op) -{ - int res; - (void)ino; - - if (!(op & LOCK_NB)) { - /* - * Blocking flock can deadlock as there is only one thread - * serving the queue. - */ - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - res = flock(lo_fi_fd(req, fi), op); - - fuse_reply_err(req, res == -1 ? errno : 0); -} - -/* types */ -/* - * Exit; process attribute unmodified if matched. - * An empty key applies to all. - */ -#define XATTR_MAP_FLAG_OK (1 << 0) -/* - * The attribute is unwanted; - * EPERM on write, hidden on read. - */ -#define XATTR_MAP_FLAG_BAD (1 << 1) -/* - * For attr that start with 'key' prepend 'prepend' - * 'key' may be empty to prepend for all attrs - * key is defined from set/remove point of view. - * Automatically reversed on read - */ -#define XATTR_MAP_FLAG_PREFIX (1 << 2) -/* - * The attribute is unsupported; - * ENOTSUP on write, hidden on read. - */ -#define XATTR_MAP_FLAG_UNSUPPORTED (1 << 3) - -/* scopes */ -/* Apply rule to get/set/remove */ -#define XATTR_MAP_FLAG_CLIENT (1 << 16) -/* Apply rule to list */ -#define XATTR_MAP_FLAG_SERVER (1 << 17) -/* Apply rule to all */ -#define XATTR_MAP_FLAG_ALL (XATTR_MAP_FLAG_SERVER | XATTR_MAP_FLAG_CLIENT) - -static void add_xattrmap_entry(struct lo_data *lo, - const XattrMapEntry *new_entry) -{ - XattrMapEntry *res = g_realloc_n(lo->xattr_map_list, - lo->xattr_map_nentries + 1, - sizeof(XattrMapEntry)); - res[lo->xattr_map_nentries++] = *new_entry; - - lo->xattr_map_list = res; -} - -static void free_xattrmap(struct lo_data *lo) -{ - XattrMapEntry *map = lo->xattr_map_list; - size_t i; - - if (!map) { - return; - } - - for (i = 0; i < lo->xattr_map_nentries; i++) { - g_free(map[i].key); - g_free(map[i].prepend); - }; - - g_free(map); - lo->xattr_map_list = NULL; - lo->xattr_map_nentries = -1; -} - -/* - * Handle the 'map' type, which is sugar for a set of commands - * for the common case of prefixing a subset or everything, - * and allowing anything not prefixed through. - * It must be the last entry in the stream, although there - * can be other entries before it. - * The form is: - * :map:key:prefix: - * - * key maybe empty in which case all entries are prefixed. - */ -static void parse_xattrmap_map(struct lo_data *lo, - const char *rule, char sep) -{ - const char *tmp; - char *key; - char *prefix; - XattrMapEntry tmp_entry; - - if (*rule != sep) { - fuse_log(FUSE_LOG_ERR, - "%s: Expecting '%c' after 'map' keyword, found '%c'\n", - __func__, sep, *rule); - exit(1); - } - - rule++; - - /* At start of 'key' field */ - tmp = strchr(rule, sep); - if (!tmp) { - fuse_log(FUSE_LOG_ERR, - "%s: Missing '%c' at end of key field in map rule\n", - __func__, sep); - exit(1); - } - - key = g_strndup(rule, tmp - rule); - rule = tmp + 1; - - /* At start of prefix field */ - tmp = strchr(rule, sep); - if (!tmp) { - fuse_log(FUSE_LOG_ERR, - "%s: Missing '%c' at end of prefix field in map rule\n", - __func__, sep); - exit(1); - } - - prefix = g_strndup(rule, tmp - rule); - rule = tmp + 1; - - /* - * This should be the end of the string, we don't allow - * any more commands after 'map'. - */ - if (*rule) { - fuse_log(FUSE_LOG_ERR, - "%s: Expecting end of command after map, found '%c'\n", - __func__, *rule); - exit(1); - } - - /* 1st: Prefix matches/everything */ - tmp_entry.flags = XATTR_MAP_FLAG_PREFIX | XATTR_MAP_FLAG_ALL; - tmp_entry.key = g_strdup(key); - tmp_entry.prepend = g_strdup(prefix); - add_xattrmap_entry(lo, &tmp_entry); - - if (!*key) { - /* Prefix all case */ - - /* 2nd: Hide any non-prefixed entries on the host */ - tmp_entry.flags = XATTR_MAP_FLAG_BAD | XATTR_MAP_FLAG_ALL; - tmp_entry.key = g_strdup(""); - tmp_entry.prepend = g_strdup(""); - add_xattrmap_entry(lo, &tmp_entry); - } else { - /* Prefix matching case */ - - /* 2nd: Hide non-prefixed but matching entries on the host */ - tmp_entry.flags = XATTR_MAP_FLAG_BAD | XATTR_MAP_FLAG_SERVER; - tmp_entry.key = g_strdup(""); /* Not used */ - tmp_entry.prepend = g_strdup(key); - add_xattrmap_entry(lo, &tmp_entry); - - /* 3rd: Stop the client accessing prefixed attributes directly */ - tmp_entry.flags = XATTR_MAP_FLAG_BAD | XATTR_MAP_FLAG_CLIENT; - tmp_entry.key = g_strdup(prefix); - tmp_entry.prepend = g_strdup(""); /* Not used */ - add_xattrmap_entry(lo, &tmp_entry); - - /* 4th: Everything else is OK */ - tmp_entry.flags = XATTR_MAP_FLAG_OK | XATTR_MAP_FLAG_ALL; - tmp_entry.key = g_strdup(""); - tmp_entry.prepend = g_strdup(""); - add_xattrmap_entry(lo, &tmp_entry); - } - - g_free(key); - g_free(prefix); -} - -static void parse_xattrmap(struct lo_data *lo) -{ - const char *map = lo->xattrmap; - const char *tmp; - int ret; - - lo->xattr_map_nentries = 0; - while (*map) { - XattrMapEntry tmp_entry; - char sep; - - if (isspace(*map)) { - map++; - continue; - } - /* The separator is the first non-space of the rule */ - sep = *map++; - if (!sep) { - break; - } - - tmp_entry.flags = 0; - /* Start of 'type' */ - if (strstart(map, "prefix", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_PREFIX; - } else if (strstart(map, "ok", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_OK; - } else if (strstart(map, "bad", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_BAD; - } else if (strstart(map, "unsupported", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_UNSUPPORTED; - } else if (strstart(map, "map", &map)) { - /* - * map is sugar that adds a number of rules, and must be - * the last entry. - */ - parse_xattrmap_map(lo, map, sep); - break; - } else { - fuse_log(FUSE_LOG_ERR, - "%s: Unexpected type;" - "Expecting 'prefix', 'ok', 'bad', 'unsupported' or 'map'" - " in rule %zu\n", __func__, lo->xattr_map_nentries); - exit(1); - } - - if (*map++ != sep) { - fuse_log(FUSE_LOG_ERR, - "%s: Missing '%c' at end of type field of rule %zu\n", - __func__, sep, lo->xattr_map_nentries); - exit(1); - } - - /* Start of 'scope' */ - if (strstart(map, "client", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_CLIENT; - } else if (strstart(map, "server", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_SERVER; - } else if (strstart(map, "all", &map)) { - tmp_entry.flags |= XATTR_MAP_FLAG_ALL; - } else { - fuse_log(FUSE_LOG_ERR, - "%s: Unexpected scope;" - " Expecting 'client', 'server', or 'all', in rule %zu\n", - __func__, lo->xattr_map_nentries); - exit(1); - } - - if (*map++ != sep) { - fuse_log(FUSE_LOG_ERR, - "%s: Expecting '%c' found '%c'" - " after scope in rule %zu\n", - __func__, sep, *map, lo->xattr_map_nentries); - exit(1); - } - - /* At start of 'key' field */ - tmp = strchr(map, sep); - if (!tmp) { - fuse_log(FUSE_LOG_ERR, - "%s: Missing '%c' at end of key field of rule %zu", - __func__, sep, lo->xattr_map_nentries); - exit(1); - } - tmp_entry.key = g_strndup(map, tmp - map); - map = tmp + 1; - - /* At start of 'prepend' field */ - tmp = strchr(map, sep); - if (!tmp) { - fuse_log(FUSE_LOG_ERR, - "%s: Missing '%c' at end of prepend field of rule %zu", - __func__, sep, lo->xattr_map_nentries); - exit(1); - } - tmp_entry.prepend = g_strndup(map, tmp - map); - map = tmp + 1; - - add_xattrmap_entry(lo, &tmp_entry); - /* End of rule - go around again for another rule */ - } - - if (!lo->xattr_map_nentries) { - fuse_log(FUSE_LOG_ERR, "Empty xattr map\n"); - exit(1); - } - - ret = xattr_map_client(lo, "security.capability", - &lo->xattr_security_capability); - if (ret) { - fuse_log(FUSE_LOG_ERR, "Failed to map security.capability: %s\n", - strerror(ret)); - exit(1); - } - if (!lo->xattr_security_capability || - !strcmp(lo->xattr_security_capability, "security.capability")) { - /* 1-1 mapping, don't need to do anything */ - free(lo->xattr_security_capability); - lo->xattr_security_capability = NULL; - } -} - -/* - * For use with getxattr/setxattr/removexattr, where the client - * gives us a name and we may need to choose a different one. - * Allocates a buffer for the result placing it in *out_name. - * If there's no change then *out_name is not set. - * Returns 0 on success - * Can return -EPERM to indicate we block a given attribute - * (in which case out_name is not allocated) - * Can return -ENOMEM to indicate out_name couldn't be allocated. - */ -static int xattr_map_client(const struct lo_data *lo, const char *client_name, - char **out_name) -{ - size_t i; - for (i = 0; i < lo->xattr_map_nentries; i++) { - const XattrMapEntry *cur_entry = lo->xattr_map_list + i; - - if ((cur_entry->flags & XATTR_MAP_FLAG_CLIENT) && - (strstart(client_name, cur_entry->key, NULL))) { - if (cur_entry->flags & XATTR_MAP_FLAG_BAD) { - return -EPERM; - } - if (cur_entry->flags & XATTR_MAP_FLAG_UNSUPPORTED) { - return -ENOTSUP; - } - if (cur_entry->flags & XATTR_MAP_FLAG_OK) { - /* Unmodified name */ - return 0; - } - if (cur_entry->flags & XATTR_MAP_FLAG_PREFIX) { - *out_name = g_try_malloc(strlen(client_name) + - strlen(cur_entry->prepend) + 1); - if (!*out_name) { - return -ENOMEM; - } - sprintf(*out_name, "%s%s", cur_entry->prepend, client_name); - return 0; - } - } - } - - return -EPERM; -} - -/* - * For use with listxattr where the server fs gives us a name and we may need - * to sanitize this for the client. - * Returns a pointer to the result in *out_name - * This is always the original string or the current string with some prefix - * removed; no reallocation is done. - * Returns 0 on success - * Can return -ENODATA to indicate the name should be dropped from the list. - */ -static int xattr_map_server(const struct lo_data *lo, const char *server_name, - const char **out_name) -{ - size_t i; - const char *end; - - for (i = 0; i < lo->xattr_map_nentries; i++) { - const XattrMapEntry *cur_entry = lo->xattr_map_list + i; - - if ((cur_entry->flags & XATTR_MAP_FLAG_SERVER) && - (strstart(server_name, cur_entry->prepend, &end))) { - if (cur_entry->flags & XATTR_MAP_FLAG_BAD || - cur_entry->flags & XATTR_MAP_FLAG_UNSUPPORTED) { - return -ENODATA; - } - if (cur_entry->flags & XATTR_MAP_FLAG_OK) { - *out_name = server_name; - return 0; - } - if (cur_entry->flags & XATTR_MAP_FLAG_PREFIX) { - /* Remove prefix */ - *out_name = end; - return 0; - } - } - } - - return -ENODATA; -} - -static bool block_xattr(struct lo_data *lo, const char *name) -{ - /* - * If user explicitly enabled posix_acl or did not provide any option, - * do not block acl. Otherwise block system.posix_acl_access and - * system.posix_acl_default xattrs. - */ - if (lo->user_posix_acl) { - return false; - } - if (!strcmp(name, "system.posix_acl_access") || - !strcmp(name, "system.posix_acl_default")) - return true; - - return false; -} - -/* - * Returns number of bytes in xattr_list after filtering on success. This - * could be zero as well if nothing is left after filtering. - * - * Returns negative error code on failure. - * xattr_list is modified in place. - */ -static int remove_blocked_xattrs(struct lo_data *lo, char *xattr_list, - unsigned in_size) -{ - size_t out_index, in_index; - - /* - * As of now we only filter out acl xattrs. If acls are enabled or - * they have not been explicitly disabled, there is nothing to - * filter. - */ - if (lo->user_posix_acl) { - return in_size; - } - - out_index = 0; - in_index = 0; - while (in_index < in_size) { - char *in_ptr = xattr_list + in_index; - - /* Length of current attribute name */ - size_t in_len = strlen(xattr_list + in_index) + 1; - - if (!block_xattr(lo, in_ptr)) { - if (in_index != out_index) { - memmove(xattr_list + out_index, xattr_list + in_index, in_len); - } - out_index += in_len; - } - in_index += in_len; - } - return out_index; -} - -static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, - size_t size) -{ - struct lo_data *lo = lo_data(req); - g_autofree char *value = NULL; - char procname[64]; - const char *name; - char *mapped_name; - struct lo_inode *inode; - ssize_t ret; - int saverr; - int fd = -1; - - if (block_xattr(lo, in_name)) { - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - mapped_name = NULL; - name = in_name; - if (lo->xattrmap) { - ret = xattr_map_client(lo, in_name, &mapped_name); - if (ret < 0) { - if (ret == -EPERM) { - ret = -ENODATA; - } - fuse_reply_err(req, -ret); - return; - } - if (mapped_name) { - name = mapped_name; - } - } - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - g_free(mapped_name); - return; - } - - saverr = ENOSYS; - if (!lo_data(req)->xattr) { - goto out; - } - - fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", - ino, name, size); - - if (size) { - value = g_try_malloc(size); - if (!value) { - goto out_err; - } - } - - sprintf(procname, "%i", inode->fd); - /* - * It is not safe to open() non-regular/non-dir files in file server - * unless O_PATH is used, so use that method for regular files/dir - * only (as it seems giving less performance overhead). - * Otherwise, call fchdir() to avoid open(). - */ - if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = openat(lo->proc_self_fd, procname, O_RDONLY); - if (fd < 0) { - goto out_err; - } - ret = fgetxattr(fd, name, value, size); - saverr = ret == -1 ? errno : 0; - } else { - /* fchdir should not fail here */ - FCHDIR_NOFAIL(lo->proc_self_fd); - ret = getxattr(procname, name, value, size); - saverr = ret == -1 ? errno : 0; - FCHDIR_NOFAIL(lo->root.fd); - } - - if (ret == -1) { - goto out; - } - if (size) { - saverr = 0; - if (ret == 0) { - goto out; - } - fuse_reply_buf(req, value, ret); - } else { - fuse_reply_xattr(req, ret); - } -out_free: - if (fd >= 0) { - close(fd); - } - - lo_inode_put(lo, &inode); - return; - -out_err: - saverr = errno; -out: - fuse_reply_err(req, saverr); - g_free(mapped_name); - goto out_free; -} - -static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) -{ - struct lo_data *lo = lo_data(req); - g_autofree char *value = NULL; - char procname[64]; - struct lo_inode *inode; - ssize_t ret; - int saverr; - int fd = -1; - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - saverr = ENOSYS; - if (!lo_data(req)->xattr) { - goto out; - } - - fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n", ino, - size); - - if (size) { - value = g_try_malloc(size); - if (!value) { - goto out_err; - } - } - - sprintf(procname, "%i", inode->fd); - if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = openat(lo->proc_self_fd, procname, O_RDONLY); - if (fd < 0) { - goto out_err; - } - ret = flistxattr(fd, value, size); - saverr = ret == -1 ? errno : 0; - } else { - /* fchdir should not fail here */ - FCHDIR_NOFAIL(lo->proc_self_fd); - ret = listxattr(procname, value, size); - saverr = ret == -1 ? errno : 0; - FCHDIR_NOFAIL(lo->root.fd); - } - - if (ret == -1) { - goto out; - } - if (size) { - saverr = 0; - if (ret == 0) { - goto out; - } - - if (lo->xattr_map_list) { - /* - * Map the names back, some attributes might be dropped, - * some shortened, but not increased, so we shouldn't - * run out of room. - */ - size_t out_index, in_index; - out_index = 0; - in_index = 0; - while (in_index < ret) { - const char *map_out; - char *in_ptr = value + in_index; - /* Length of current attribute name */ - size_t in_len = strlen(value + in_index) + 1; - - int mapret = xattr_map_server(lo, in_ptr, &map_out); - if (mapret != -ENODATA && mapret != 0) { - /* Shouldn't happen */ - saverr = -mapret; - goto out; - } - if (mapret == 0) { - /* Either unchanged, or truncated */ - size_t out_len; - if (map_out != in_ptr) { - /* +1 copies the NIL */ - out_len = strlen(map_out) + 1; - } else { - /* No change */ - out_len = in_len; - } - /* - * Move result along, may still be needed for an unchanged - * entry if a previous entry was changed. - */ - memmove(value + out_index, map_out, out_len); - - out_index += out_len; - } - in_index += in_len; - } - ret = out_index; - if (ret == 0) { - goto out; - } - } - - ret = remove_blocked_xattrs(lo, value, ret); - if (ret <= 0) { - saverr = -ret; - goto out; - } - fuse_reply_buf(req, value, ret); - } else { - /* - * xattrmap only ever shortens the result, - * so we don't need to do anything clever with the - * allocation length here. - */ - fuse_reply_xattr(req, ret); - } -out_free: - if (fd >= 0) { - close(fd); - } - - lo_inode_put(lo, &inode); - return; - -out_err: - saverr = errno; -out: - fuse_reply_err(req, saverr); - goto out_free; -} - -static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, - const char *value, size_t size, int flags, - uint32_t extra_flags) -{ - char procname[64]; - const char *name; - char *mapped_name; - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - ssize_t ret; - int saverr; - int fd = -1; - bool switched_creds = false; - bool cap_fsetid_dropped = false; - struct lo_cred old = {}; - - if (block_xattr(lo, in_name)) { - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - mapped_name = NULL; - name = in_name; - if (lo->xattrmap) { - ret = xattr_map_client(lo, in_name, &mapped_name); - if (ret < 0) { - fuse_reply_err(req, -ret); - return; - } - if (mapped_name) { - name = mapped_name; - } - } - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - g_free(mapped_name); - return; - } - - saverr = ENOSYS; - if (!lo_data(req)->xattr) { - goto out; - } - - fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 - ", name=%s value=%s size=%zd)\n", ino, name, value, size); - - sprintf(procname, "%i", inode->fd); - /* - * If we are setting posix access acl and if SGID needs to be - * cleared, then switch to caller's gid and drop CAP_FSETID - * and that should make sure host kernel clears SGID. - * - * This probably will not work when we support idmapped mounts. - * In that case we will need to find a non-root gid and switch - * to it. (Instead of gid in request). Fix it when we support - * idmapped mounts. - */ - if (lo->posix_acl && !strcmp(name, "system.posix_acl_access") - && (extra_flags & FUSE_SETXATTR_ACL_KILL_SGID)) { - ret = lo_drop_cap_change_cred(req, &old, false, "FSETID", - &cap_fsetid_dropped); - if (ret) { - saverr = ret; - goto out; - } - switched_creds = true; - } - if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = openat(lo->proc_self_fd, procname, O_RDONLY); - if (fd < 0) { - saverr = errno; - goto out; - } - ret = fsetxattr(fd, name, value, size, flags); - saverr = ret == -1 ? errno : 0; - } else { - /* fchdir should not fail here */ - FCHDIR_NOFAIL(lo->proc_self_fd); - ret = setxattr(procname, name, value, size, flags); - saverr = ret == -1 ? errno : 0; - FCHDIR_NOFAIL(lo->root.fd); - } - if (switched_creds) { - if (cap_fsetid_dropped) - lo_restore_cred_gain_cap(&old, false, "FSETID"); - else - lo_restore_cred(&old, false); - } - -out: - if (fd >= 0) { - close(fd); - } - - lo_inode_put(lo, &inode); - g_free(mapped_name); - fuse_reply_err(req, saverr); -} - -static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) -{ - char procname[64]; - const char *name; - char *mapped_name; - struct lo_data *lo = lo_data(req); - struct lo_inode *inode; - ssize_t ret; - int saverr; - int fd = -1; - - if (block_xattr(lo, in_name)) { - fuse_reply_err(req, EOPNOTSUPP); - return; - } - - mapped_name = NULL; - name = in_name; - if (lo->xattrmap) { - ret = xattr_map_client(lo, in_name, &mapped_name); - if (ret < 0) { - fuse_reply_err(req, -ret); - return; - } - if (mapped_name) { - name = mapped_name; - } - } - - inode = lo_inode(req, ino); - if (!inode) { - fuse_reply_err(req, EBADF); - g_free(mapped_name); - return; - } - - saverr = ENOSYS; - if (!lo_data(req)->xattr) { - goto out; - } - - fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n", ino, - name); - - sprintf(procname, "%i", inode->fd); - if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) { - fd = openat(lo->proc_self_fd, procname, O_RDONLY); - if (fd < 0) { - saverr = errno; - goto out; - } - ret = fremovexattr(fd, name); - saverr = ret == -1 ? errno : 0; - } else { - /* fchdir should not fail here */ - FCHDIR_NOFAIL(lo->proc_self_fd); - ret = removexattr(procname, name); - saverr = ret == -1 ? errno : 0; - FCHDIR_NOFAIL(lo->root.fd); - } - -out: - if (fd >= 0) { - close(fd); - } - - lo_inode_put(lo, &inode); - g_free(mapped_name); - fuse_reply_err(req, saverr); -} - -#ifdef HAVE_COPY_FILE_RANGE -static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, - struct fuse_file_info *fi_in, fuse_ino_t ino_out, - off_t off_out, struct fuse_file_info *fi_out, - size_t len, int flags) -{ - int in_fd, out_fd; - ssize_t res; - - in_fd = lo_fi_fd(req, fi_in); - out_fd = lo_fi_fd(req, fi_out); - - fuse_log(FUSE_LOG_DEBUG, - "lo_copy_file_range(ino=%" PRIu64 "/fd=%d, " - "off=%ju, ino=%" PRIu64 "/fd=%d, " - "off=%ju, size=%zd, flags=0x%x)\n", - ino_in, in_fd, (intmax_t)off_in, - ino_out, out_fd, (intmax_t)off_out, len, flags); - - res = copy_file_range(in_fd, &off_in, out_fd, &off_out, len, flags); - if (res < 0) { - fuse_reply_err(req, errno); - } else { - fuse_reply_write(req, res); - } -} -#endif - -static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, - struct fuse_file_info *fi) -{ - off_t res; - - (void)ino; - res = lseek(lo_fi_fd(req, fi), off, whence); - if (res != -1) { - fuse_reply_lseek(req, res); - } else { - fuse_reply_err(req, errno); - } -} - -static int lo_do_syncfs(struct lo_data *lo, struct lo_inode *inode) -{ - int fd, ret = 0; - - fuse_log(FUSE_LOG_DEBUG, "lo_do_syncfs(ino=%" PRIu64 ")\n", - inode->fuse_ino); - - fd = lo_inode_open(lo, inode, O_RDONLY); - if (fd < 0) { - return -fd; - } - - if (syncfs(fd) < 0) { - ret = errno; - } - - close(fd); - return ret; -} - -static void lo_syncfs(fuse_req_t req, fuse_ino_t ino) -{ - struct lo_data *lo = lo_data(req); - struct lo_inode *inode = lo_inode(req, ino); - int err; - - if (!inode) { - fuse_reply_err(req, EBADF); - return; - } - - err = lo_do_syncfs(lo, inode); - lo_inode_put(lo, &inode); - - /* - * If submounts aren't announced, the client only sends a request to - * sync the root inode. TODO: Track submounts internally and iterate - * over them as well. - */ - - fuse_reply_err(req, err); -} - -static void lo_destroy(void *userdata) -{ - struct lo_data *lo = (struct lo_data *)userdata; - - pthread_mutex_lock(&lo->mutex); - while (true) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init(&iter, lo->inodes); - if (!g_hash_table_iter_next(&iter, &key, &value)) { - break; - } - - struct lo_inode *inode = value; - unref_inode(lo, inode, inode->nlookup); - } - pthread_mutex_unlock(&lo->mutex); -} - -static struct fuse_lowlevel_ops lo_oper = { - .init = lo_init, - .lookup = lo_lookup, - .mkdir = lo_mkdir, - .mknod = lo_mknod, - .symlink = lo_symlink, - .link = lo_link, - .unlink = lo_unlink, - .rmdir = lo_rmdir, - .rename = lo_rename, - .forget = lo_forget, - .forget_multi = lo_forget_multi, - .getattr = lo_getattr, - .setattr = lo_setattr, - .readlink = lo_readlink, - .opendir = lo_opendir, - .readdir = lo_readdir, - .readdirplus = lo_readdirplus, - .releasedir = lo_releasedir, - .fsyncdir = lo_fsyncdir, - .create = lo_create, - .getlk = lo_getlk, - .setlk = lo_setlk, - .open = lo_open, - .release = lo_release, - .flush = lo_flush, - .fsync = lo_fsync, - .read = lo_read, - .write_buf = lo_write_buf, - .statfs = lo_statfs, - .fallocate = lo_fallocate, - .flock = lo_flock, - .getxattr = lo_getxattr, - .listxattr = lo_listxattr, - .setxattr = lo_setxattr, - .removexattr = lo_removexattr, -#ifdef HAVE_COPY_FILE_RANGE - .copy_file_range = lo_copy_file_range, -#endif - .lseek = lo_lseek, - .syncfs = lo_syncfs, - .destroy = lo_destroy, -}; - -/* Print vhost-user.json backend program capabilities */ -static void print_capabilities(void) -{ - printf("{\n"); - printf(" \"type\": \"fs\"\n"); - printf("}\n"); -} - -/* - * Drop all Linux capabilities because the wait parent process only needs to - * sit in waitpid(2) and terminate. - */ -static void setup_wait_parent_capabilities(void) -{ - capng_setpid(syscall(SYS_gettid)); - capng_clear(CAPNG_SELECT_BOTH); - capng_apply(CAPNG_SELECT_BOTH); -} - -/* - * Move to a new mount, net, and pid namespaces to isolate this process. - */ -static void setup_namespaces(struct lo_data *lo, struct fuse_session *se) -{ - pid_t child; - - /* - * Create a new pid namespace for *child* processes. We'll have to - * fork in order to enter the new pid namespace. A new mount namespace - * is also needed so that we can remount /proc for the new pid - * namespace. - * - * Our UNIX domain sockets have been created. Now we can move to - * an empty network namespace to prevent TCP/IP and other network - * activity in case this process is compromised. - */ - if (unshare(CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET) != 0) { - fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWPID | CLONE_NEWNS): %m\n"); - exit(1); - } - - child = fork(); - if (child < 0) { - fuse_log(FUSE_LOG_ERR, "fork() failed: %m\n"); - exit(1); - } - if (child > 0) { - pid_t waited; - int wstatus; - - setup_wait_parent_capabilities(); - - /* The parent waits for the child */ - do { - waited = waitpid(child, &wstatus, 0); - } while (waited < 0 && errno == EINTR && !se->exited); - - /* We were terminated by a signal, see fuse_signals.c */ - if (se->exited) { - exit(0); - } - - if (WIFEXITED(wstatus)) { - exit(WEXITSTATUS(wstatus)); - } - - exit(1); - } - - /* Send us SIGTERM when the parent thread terminates, see prctl(2) */ - prctl(PR_SET_PDEATHSIG, SIGTERM); - - /* - * If the mounts have shared propagation then we want to opt out so our - * mount changes don't affect the parent mount namespace. - */ - if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0) { - fuse_log(FUSE_LOG_ERR, "mount(/, MS_REC|MS_SLAVE): %m\n"); - exit(1); - } - - /* The child must remount /proc to use the new pid namespace */ - if (mount("proc", "/proc", "proc", - MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) { - fuse_log(FUSE_LOG_ERR, "mount(/proc): %m\n"); - exit(1); - } - - /* Get the /proc/self/task descriptor */ - lo->proc_self_task = open("/proc/self/task/", O_PATH); - if (lo->proc_self_task == -1) { - fuse_log(FUSE_LOG_ERR, "open(/proc/self/task, O_PATH): %m\n"); - exit(1); - } - - lo->use_fscreate = is_fscreate_usable(lo); - - /* - * We only need /proc/self/fd. Prevent ".." from accessing parent - * directories of /proc/self/fd by bind-mounting it over /proc. Since / was - * previously remounted with MS_REC | MS_SLAVE this mount change only - * affects our process. - */ - if (mount("/proc/self/fd", "/proc", NULL, MS_BIND, NULL) < 0) { - fuse_log(FUSE_LOG_ERR, "mount(/proc/self/fd, MS_BIND): %m\n"); - exit(1); - } - - /* Get the /proc (actually /proc/self/fd, see above) file descriptor */ - lo->proc_self_fd = open("/proc", O_PATH); - if (lo->proc_self_fd == -1) { - fuse_log(FUSE_LOG_ERR, "open(/proc, O_PATH): %m\n"); - exit(1); - } -} - -/* - * Capture the capability state, we'll need to restore this for individual - * threads later; see load_capng. - */ -static void setup_capng(void) -{ - /* Note this accesses /proc so has to happen before the sandbox */ - if (capng_get_caps_process()) { - fuse_log(FUSE_LOG_ERR, "capng_get_caps_process\n"); - exit(1); - } - pthread_mutex_init(&cap.mutex, NULL); - pthread_mutex_lock(&cap.mutex); - cap.saved = capng_save_state(); - if (!cap.saved) { - fuse_log(FUSE_LOG_ERR, "capng_save_state\n"); - exit(1); - } - pthread_mutex_unlock(&cap.mutex); -} - -static void cleanup_capng(void) -{ - free(cap.saved); - cap.saved = NULL; - pthread_mutex_destroy(&cap.mutex); -} - - -/* - * Make the source directory our root so symlinks cannot escape and no other - * files are accessible. Assumes unshare(CLONE_NEWNS) was already called. - */ -static void setup_mounts(const char *source) -{ - int oldroot; - int newroot; - - if (mount(source, source, NULL, MS_BIND | MS_REC, NULL) < 0) { - fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source); - exit(1); - } - - /* This magic is based on lxc's lxc_pivot_root() */ - oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (oldroot < 0) { - fuse_log(FUSE_LOG_ERR, "open(/): %m\n"); - exit(1); - } - - newroot = open(source, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (newroot < 0) { - fuse_log(FUSE_LOG_ERR, "open(%s): %m\n", source); - exit(1); - } - - if (fchdir(newroot) < 0) { - fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n"); - exit(1); - } - - if (syscall(__NR_pivot_root, ".", ".") < 0) { - fuse_log(FUSE_LOG_ERR, "pivot_root(., .): %m\n"); - exit(1); - } - - if (fchdir(oldroot) < 0) { - fuse_log(FUSE_LOG_ERR, "fchdir(oldroot): %m\n"); - exit(1); - } - - if (mount("", ".", "", MS_SLAVE | MS_REC, NULL) < 0) { - fuse_log(FUSE_LOG_ERR, "mount(., MS_SLAVE | MS_REC): %m\n"); - exit(1); - } - - if (umount2(".", MNT_DETACH) < 0) { - fuse_log(FUSE_LOG_ERR, "umount2(., MNT_DETACH): %m\n"); - exit(1); - } - - if (fchdir(newroot) < 0) { - fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n"); - exit(1); - } - - close(newroot); - close(oldroot); -} - -/* - * Only keep capabilities in allowlist that are needed for file system operation - * The (possibly NULL) modcaps_in string passed in is free'd before exit. - */ -static void setup_capabilities(char *modcaps_in) -{ - char *modcaps = modcaps_in; - pthread_mutex_lock(&cap.mutex); - capng_restore_state(&cap.saved); - - /* - * Add to allowlist file system-related capabilities that are needed for a - * file server to act like root. Drop everything else like networking and - * sysadmin capabilities. - * - * Exclusions: - * 1. CAP_LINUX_IMMUTABLE is not included because it's only used via ioctl - * and we don't support that. - * 2. CAP_MAC_OVERRIDE is not included because it only seems to be - * used by the Smack LSM. Omit it until there is demand for it. - */ - capng_setpid(syscall(SYS_gettid)); - capng_clear(CAPNG_SELECT_BOTH); - if (capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE, - CAP_CHOWN, - CAP_DAC_OVERRIDE, - CAP_FOWNER, - CAP_FSETID, - CAP_SETGID, - CAP_SETUID, - CAP_MKNOD, - CAP_SETFCAP, - -1)) { - fuse_log(FUSE_LOG_ERR, "%s: capng_updatev failed\n", __func__); - exit(1); - } - - /* - * The modcaps option is a colon separated list of caps, - * each preceded by either + or -. - */ - while (modcaps) { - capng_act_t action; - int cap; - - char *next = strchr(modcaps, ':'); - if (next) { - *next = '\0'; - next++; - } - - switch (modcaps[0]) { - case '+': - action = CAPNG_ADD; - break; - - case '-': - action = CAPNG_DROP; - break; - - default: - fuse_log(FUSE_LOG_ERR, - "%s: Expecting '+'/'-' in modcaps but found '%c'\n", - __func__, modcaps[0]); - exit(1); - } - cap = capng_name_to_capability(modcaps + 1); - if (cap < 0) { - fuse_log(FUSE_LOG_ERR, "%s: Unknown capability '%s'\n", __func__, - modcaps); - exit(1); - } - if (capng_update(action, CAPNG_PERMITTED | CAPNG_EFFECTIVE, cap)) { - fuse_log(FUSE_LOG_ERR, "%s: capng_update failed for '%s'\n", - __func__, modcaps); - exit(1); - } - - modcaps = next; - } - g_free(modcaps_in); - - if (capng_apply(CAPNG_SELECT_BOTH)) { - fuse_log(FUSE_LOG_ERR, "%s: capng_apply failed\n", __func__); - exit(1); - } - - cap.saved = capng_save_state(); - if (!cap.saved) { - fuse_log(FUSE_LOG_ERR, "%s: capng_save_state failed\n", __func__); - exit(1); - } - pthread_mutex_unlock(&cap.mutex); -} - -/* - * Use chroot as a weaker sandbox for environments where the process is - * launched without CAP_SYS_ADMIN. - */ -static void setup_chroot(struct lo_data *lo) -{ - lo->proc_self_fd = open("/proc/self/fd", O_PATH); - if (lo->proc_self_fd == -1) { - fuse_log(FUSE_LOG_ERR, "open(\"/proc/self/fd\", O_PATH): %m\n"); - exit(1); - } - - lo->proc_self_task = open("/proc/self/task", O_PATH); - if (lo->proc_self_fd == -1) { - fuse_log(FUSE_LOG_ERR, "open(\"/proc/self/task\", O_PATH): %m\n"); - exit(1); - } - - lo->use_fscreate = is_fscreate_usable(lo); - - /* - * Make the shared directory the file system root so that FUSE_OPEN - * (lo_open()) cannot escape the shared directory by opening a symlink. - * - * The chroot(2) syscall is later disabled by seccomp and the - * CAP_SYS_CHROOT capability is dropped so that tampering with the chroot - * is not possible. - * - * However, it's still possible to escape the chroot via lo->proc_self_fd - * but that requires first gaining control of the process. - */ - if (chroot(lo->source) != 0) { - fuse_log(FUSE_LOG_ERR, "chroot(\"%s\"): %m\n", lo->source); - exit(1); - } - - /* Move into the chroot */ - if (chdir("/") != 0) { - fuse_log(FUSE_LOG_ERR, "chdir(\"/\"): %m\n"); - exit(1); - } -} - -/* - * Lock down this process to prevent access to other processes or files outside - * source directory. This reduces the impact of arbitrary code execution bugs. - */ -static void setup_sandbox(struct lo_data *lo, struct fuse_session *se, - bool enable_syslog) -{ - if (lo->sandbox == SANDBOX_NAMESPACE) { - setup_namespaces(lo, se); - setup_mounts(lo->source); - } else { - setup_chroot(lo); - } - - setup_seccomp(enable_syslog); - setup_capabilities(g_strdup(lo->modcaps)); -} - -/* Set the maximum number of open file descriptors */ -static void setup_nofile_rlimit(unsigned long rlimit_nofile) -{ - struct rlimit rlim = { - .rlim_cur = rlimit_nofile, - .rlim_max = rlimit_nofile, - }; - - if (rlimit_nofile == 0) { - return; /* nothing to do */ - } - - if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { - /* Ignore SELinux denials */ - if (errno == EPERM) { - return; - } - - fuse_log(FUSE_LOG_ERR, "setrlimit(RLIMIT_NOFILE): %m\n"); - exit(1); - } -} - -G_GNUC_PRINTF(2, 0) -static void log_func(enum fuse_log_level level, const char *fmt, va_list ap) -{ - g_autofree char *localfmt = NULL; - char buf[64]; - - if (current_log_level < level) { - return; - } - - if (current_log_level == FUSE_LOG_DEBUG) { - if (use_syslog) { - /* no timestamp needed */ - localfmt = g_strdup_printf("[ID: %08ld] %s", syscall(__NR_gettid), - fmt); - } else { - g_autoptr(GDateTime) now = g_date_time_new_now_utc(); - g_autofree char *nowstr = g_date_time_format(now, - "%Y-%m-%d %H:%M:%S.%%06d%z"); - snprintf(buf, 64, nowstr, g_date_time_get_microsecond(now)); - localfmt = g_strdup_printf("[%s] [ID: %08ld] %s", - buf, syscall(__NR_gettid), fmt); - } - fmt = localfmt; - } - - if (use_syslog) { - int priority = LOG_ERR; - switch (level) { - case FUSE_LOG_EMERG: - priority = LOG_EMERG; - break; - case FUSE_LOG_ALERT: - priority = LOG_ALERT; - break; - case FUSE_LOG_CRIT: - priority = LOG_CRIT; - break; - case FUSE_LOG_ERR: - priority = LOG_ERR; - break; - case FUSE_LOG_WARNING: - priority = LOG_WARNING; - break; - case FUSE_LOG_NOTICE: - priority = LOG_NOTICE; - break; - case FUSE_LOG_INFO: - priority = LOG_INFO; - break; - case FUSE_LOG_DEBUG: - priority = LOG_DEBUG; - break; - } - vsyslog(priority, fmt, ap); - } else { - vfprintf(stderr, fmt, ap); - } -} - -static void setup_root(struct lo_data *lo, struct lo_inode *root) -{ - int fd, res; - struct stat stat; - uint64_t mnt_id; - - fd = open("/", O_PATH); - if (fd == -1) { - fuse_log(FUSE_LOG_ERR, "open(%s, O_PATH): %m\n", lo->source); - exit(1); - } - - res = do_statx(lo, fd, "", &stat, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, - &mnt_id); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "fstatat(%s): %m\n", lo->source); - exit(1); - } - - root->filetype = S_IFDIR; - root->fd = fd; - root->key.ino = stat.st_ino; - root->key.dev = stat.st_dev; - root->key.mnt_id = mnt_id; - root->nlookup = 2; - g_atomic_int_set(&root->refcount, 2); - if (lo->posix_lock) { - pthread_mutex_init(&root->plock_mutex, NULL); - root->posix_locks = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, posix_locks_value_destroy); - } -} - -static guint lo_key_hash(gconstpointer key) -{ - const struct lo_key *lkey = key; - - return (guint)lkey->ino + (guint)lkey->dev + (guint)lkey->mnt_id; -} - -static gboolean lo_key_equal(gconstpointer a, gconstpointer b) -{ - const struct lo_key *la = a; - const struct lo_key *lb = b; - - return la->ino == lb->ino && la->dev == lb->dev && la->mnt_id == lb->mnt_id; -} - -static void fuse_lo_data_cleanup(struct lo_data *lo) -{ - if (lo->inodes) { - g_hash_table_destroy(lo->inodes); - } - - if (lo->root.posix_locks) { - g_hash_table_destroy(lo->root.posix_locks); - } - lo_map_destroy(&lo->fd_map); - lo_map_destroy(&lo->dirp_map); - lo_map_destroy(&lo->ino_map); - - if (lo->proc_self_fd >= 0) { - close(lo->proc_self_fd); - } - - if (lo->proc_self_task >= 0) { - close(lo->proc_self_task); - } - - if (lo->root.fd >= 0) { - close(lo->root.fd); - } - - free(lo->xattrmap); - free_xattrmap(lo); - free(lo->xattr_security_capability); - free(lo->source); -} - -static void qemu_version(void) -{ - printf("virtiofsd version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n"); -} - -int main(int argc, char *argv[]) -{ - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_session *se; - struct fuse_cmdline_opts opts; - struct lo_data lo = { - .sandbox = SANDBOX_NAMESPACE, - .debug = 0, - .writeback = 0, - .posix_lock = 0, - .allow_direct_io = 0, - .proc_self_fd = -1, - .proc_self_task = -1, - .user_killpriv_v2 = -1, - .user_posix_acl = -1, - .user_security_label = -1, - }; - struct lo_map_elem *root_elem; - struct lo_map_elem *reserve_elem; - int ret = -1; - - /* Initialize time conversion information for localtime_r(). */ - tzset(); - - /* Don't mask creation mode, kernel already did that */ - umask(0); - - qemu_init_exec_dir(argv[0]); - - drop_supplementary_groups(); - - pthread_mutex_init(&lo.mutex, NULL); - lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal); - lo.root.fd = -1; - lo.root.fuse_ino = FUSE_ROOT_ID; - lo.cache = CACHE_AUTO; - - /* - * Set up the ino map like this: - * [0] Reserved (will not be used) - * [1] Root inode - */ - lo_map_init(&lo.ino_map); - reserve_elem = lo_map_reserve(&lo.ino_map, 0); - if (!reserve_elem) { - fuse_log(FUSE_LOG_ERR, "failed to alloc reserve_elem.\n"); - goto err_out1; - } - reserve_elem->in_use = false; - root_elem = lo_map_reserve(&lo.ino_map, lo.root.fuse_ino); - if (!root_elem) { - fuse_log(FUSE_LOG_ERR, "failed to alloc root_elem.\n"); - goto err_out1; - } - root_elem->inode = &lo.root; - - lo_map_init(&lo.dirp_map); - lo_map_init(&lo.fd_map); - - if (fuse_parse_cmdline(&args, &opts) != 0) { - goto err_out1; - } - fuse_set_log_func(log_func); - use_syslog = opts.syslog; - if (use_syslog) { - openlog("virtiofsd", LOG_PID, LOG_DAEMON); - } - - if (opts.show_help) { - printf("usage: %s [options]\n\n", argv[0]); - fuse_cmdline_help(); - printf(" -o source=PATH shared directory tree\n"); - fuse_lowlevel_help(); - ret = 0; - goto err_out1; - } else if (opts.show_version) { - qemu_version(); - fuse_lowlevel_version(); - ret = 0; - goto err_out1; - } else if (opts.print_capabilities) { - print_capabilities(); - ret = 0; - goto err_out1; - } - - if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) { - goto err_out1; - } - - if (opts.log_level != 0) { - current_log_level = opts.log_level; - } else { - /* default log level is INFO */ - current_log_level = FUSE_LOG_INFO; - } - lo.debug = opts.debug; - if (lo.debug) { - current_log_level = FUSE_LOG_DEBUG; - } - if (lo.source) { - struct stat stat; - int res; - - res = lstat(lo.source, &stat); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n", - lo.source); - exit(1); - } - if (!S_ISDIR(stat.st_mode)) { - fuse_log(FUSE_LOG_ERR, "source is not a directory\n"); - exit(1); - } - } else { - lo.source = strdup("/"); - if (!lo.source) { - fuse_log(FUSE_LOG_ERR, "failed to strdup source\n"); - goto err_out1; - } - } - - if (lo.xattrmap) { - lo.xattr = 1; - parse_xattrmap(&lo); - } - - if (!lo.timeout_set) { - switch (lo.cache) { - case CACHE_NONE: - lo.timeout = 0.0; - break; - - case CACHE_AUTO: - lo.timeout = 1.0; - break; - - case CACHE_ALWAYS: - lo.timeout = 86400.0; - break; - } - } else if (lo.timeout < 0) { - fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", lo.timeout); - exit(1); - } - - if (lo.user_posix_acl == 1 && !lo.xattr) { - fuse_log(FUSE_LOG_ERR, "Can't enable posix ACLs. xattrs are disabled." - "\n"); - exit(1); - } - - lo.use_statx = true; - - se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); - if (se == NULL) { - goto err_out1; - } - - if (fuse_set_signal_handlers(se) != 0) { - goto err_out2; - } - - if (fuse_session_mount(se) != 0) { - goto err_out3; - } - - fuse_daemonize(opts.foreground); - - setup_nofile_rlimit(opts.rlimit_nofile); - - /* Must be before sandbox since it wants /proc */ - setup_capng(); - - setup_sandbox(&lo, se, opts.syslog); - - setup_root(&lo, &lo.root); - /* Block until ctrl+c or fusermount -u */ - ret = virtio_loop(se); - - fuse_session_unmount(se); - cleanup_capng(); -err_out3: - fuse_remove_signal_handlers(se); -err_out2: - fuse_session_destroy(se); -err_out1: - fuse_opt_free_args(&args); - - fuse_lo_data_cleanup(&lo); - - return ret ? 1 : 0; -} diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c deleted file mode 100644 index 0033dab493..0000000000 --- a/tools/virtiofsd/passthrough_seccomp.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Seccomp sandboxing for virtiofsd - * - * Copyright (C) 2019 Red Hat, Inc. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include "qemu/osdep.h" -#include "passthrough_seccomp.h" -#include "fuse_i.h" -#include "fuse_log.h" -#include - -/* Bodge for libseccomp 2.4.2 which broke ppoll */ -#if !defined(__SNR_ppoll) && defined(__SNR_brk) -#ifdef __NR_ppoll -#define __SNR_ppoll __NR_ppoll -#else -#define __SNR_ppoll __PNR_ppoll -#endif -#endif - -static const int syscall_allowlist[] = { - /* TODO ireg sem*() syscalls */ - SCMP_SYS(brk), - SCMP_SYS(capget), /* For CAP_FSETID */ - SCMP_SYS(capset), - SCMP_SYS(clock_gettime), - SCMP_SYS(clone), -#ifdef __NR_clone3 - SCMP_SYS(clone3), -#endif - SCMP_SYS(close), - SCMP_SYS(copy_file_range), - SCMP_SYS(dup), - SCMP_SYS(eventfd2), - SCMP_SYS(exit), - SCMP_SYS(exit_group), - SCMP_SYS(fallocate), - SCMP_SYS(fchdir), - SCMP_SYS(fchmod), - SCMP_SYS(fchmodat), - SCMP_SYS(fchownat), - SCMP_SYS(fcntl), - SCMP_SYS(fdatasync), - SCMP_SYS(fgetxattr), - SCMP_SYS(flistxattr), - SCMP_SYS(flock), - SCMP_SYS(fremovexattr), - SCMP_SYS(fsetxattr), - SCMP_SYS(fstat), - SCMP_SYS(fstatfs), - SCMP_SYS(fstatfs64), - SCMP_SYS(fsync), - SCMP_SYS(ftruncate), - SCMP_SYS(futex), - SCMP_SYS(getdents), - SCMP_SYS(getdents64), - SCMP_SYS(getegid), - SCMP_SYS(geteuid), - SCMP_SYS(getpid), - SCMP_SYS(gettid), - SCMP_SYS(gettimeofday), - SCMP_SYS(getxattr), - SCMP_SYS(linkat), - SCMP_SYS(listxattr), - SCMP_SYS(lseek), - SCMP_SYS(_llseek), /* For POWER */ - SCMP_SYS(madvise), - SCMP_SYS(mkdirat), - SCMP_SYS(mknodat), - SCMP_SYS(mmap), - SCMP_SYS(mprotect), - SCMP_SYS(mremap), - SCMP_SYS(munmap), - SCMP_SYS(newfstatat), - SCMP_SYS(statx), - SCMP_SYS(open), - SCMP_SYS(openat), - SCMP_SYS(ppoll), - SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */ - SCMP_SYS(preadv), - SCMP_SYS(pread64), - SCMP_SYS(pwritev), - SCMP_SYS(pwrite64), - SCMP_SYS(read), - SCMP_SYS(readlinkat), - SCMP_SYS(recvmsg), - SCMP_SYS(renameat), - SCMP_SYS(renameat2), - SCMP_SYS(removexattr), - SCMP_SYS(restart_syscall), -#ifdef __NR_rseq - SCMP_SYS(rseq), /* required since glibc 2.35 */ -#endif - SCMP_SYS(rt_sigaction), - SCMP_SYS(rt_sigprocmask), - SCMP_SYS(rt_sigreturn), - SCMP_SYS(sched_getattr), - SCMP_SYS(sched_setattr), - SCMP_SYS(sendmsg), - SCMP_SYS(setresgid), - SCMP_SYS(setresuid), -#ifdef __NR_setresgid32 - SCMP_SYS(setresgid32), -#endif -#ifdef __NR_setresuid32 - SCMP_SYS(setresuid32), -#endif - SCMP_SYS(set_robust_list), - SCMP_SYS(setxattr), - SCMP_SYS(sigreturn), - SCMP_SYS(symlinkat), - SCMP_SYS(syncfs), - SCMP_SYS(time), /* Rarely needed, except on static builds */ - SCMP_SYS(tgkill), - SCMP_SYS(unlinkat), - SCMP_SYS(unshare), - SCMP_SYS(utimensat), - SCMP_SYS(write), - SCMP_SYS(writev), - SCMP_SYS(umask), -}; - -/* Syscalls used when --syslog is enabled */ -static const int syscall_allowlist_syslog[] = { - SCMP_SYS(send), - SCMP_SYS(sendto), -}; - -static void add_allowlist(scmp_filter_ctx ctx, const int syscalls[], size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) { - fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n", - syscalls[i]); - exit(1); - } - } -} - -void setup_seccomp(bool enable_syslog) -{ - scmp_filter_ctx ctx; - -#ifdef SCMP_ACT_KILL_PROCESS - ctx = seccomp_init(SCMP_ACT_KILL_PROCESS); - /* Handle a newer libseccomp but an older kernel */ - if (!ctx && errno == EOPNOTSUPP) { - ctx = seccomp_init(SCMP_ACT_TRAP); - } -#else - ctx = seccomp_init(SCMP_ACT_TRAP); -#endif - if (!ctx) { - fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n"); - exit(1); - } - - add_allowlist(ctx, syscall_allowlist, G_N_ELEMENTS(syscall_allowlist)); - if (enable_syslog) { - add_allowlist(ctx, syscall_allowlist_syslog, - G_N_ELEMENTS(syscall_allowlist_syslog)); - } - - /* libvhost-user calls this for post-copy migration, we don't need it */ - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS), - SCMP_SYS(userfaultfd), 0) != 0) { - fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n"); - exit(1); - } - - if (seccomp_load(ctx) < 0) { - fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n"); - exit(1); - } - - seccomp_release(ctx); -} diff --git a/tools/virtiofsd/passthrough_seccomp.h b/tools/virtiofsd/passthrough_seccomp.h deleted file mode 100644 index 12674fc050..0000000000 --- a/tools/virtiofsd/passthrough_seccomp.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Seccomp sandboxing for virtiofsd - * - * Copyright (C) 2019 Red Hat, Inc. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef VIRTIOFSD_PASSTHROUGH_SECCOMP_H -#define VIRTIOFSD_PASSTHROUGH_SECCOMP_H - -void setup_seccomp(bool enable_syslog); - -#endif /* VIRTIOFSD_PASSTHROUGH_SECCOMP_H */ From a6bfdaed4a735a2cf59f265e6955fe2adcc99637 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 18 Jan 2023 12:34:43 +0000 Subject: [PATCH 761/814] virtiofsd: Swing deprecated message to removed-features Move the deprecation message, since it's now gone. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stefan Hajnoczi --- docs/about/deprecated.rst | 18 ------------------ docs/about/removed-features.rst | 13 +++++++++++++ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 2827b0c0be..ee95bcb1a6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -330,24 +330,6 @@ versions, aliases will point to newer CPU model versions depending on the machine type, so management software must resolve CPU model aliases before starting a virtual machine. -Tools ------ - -virtiofsd -''''''''' - -There is a new Rust implementation of ``virtiofsd`` at -``https://gitlab.com/virtio-fs/virtiofsd``; -since this is now marked stable, new development should be done on that -rather than the existing C version in the QEMU tree. -The C version will still accept fixes and patches that -are already in development for the moment, but will eventually -be deleted from this tree. -New deployments should use the Rust version, and existing systems -should consider moving to it. The command line and feature set -is very close and moving should be simple. - - QEMU guest agent ---------------- diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index e901637ce5..5b258b446b 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -889,3 +889,16 @@ The VXHS code did not compile since v2.12.0. It was removed in 5.1. The corresponding upstream server project is no longer maintained. Users are recommended to switch to an alternative distributed block device driver such as RBD. + +Tools +----- + +virtiofsd (removed in 8.0) +'''''''''''''''''''''''''' + +There is a newer Rust implementation of ``virtiofsd`` at +``https://gitlab.com/virtio-fs/virtiofsd``; this has been +stable for some time and is now widely used. +The command line and feature set is very close to the removed +C implementation. + From 93d7620c251059c08ffb9cf09b27ec6497081b48 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:20 +0200 Subject: [PATCH 762/814] linux-headers: Update to v6.2-rc8 Update to commit ceaa837f96ad ("Linux 6.2-rc8"). Signed-off-by: Avihai Horon Link: https://lore.kernel.org/r/20230216143630.25610-2-avihaih@nvidia.com Signed-off-by: Alex Williamson --- include/standard-headers/drm/drm_fourcc.h | 29 ++++ include/standard-headers/linux/ethtool.h | 18 ++- include/standard-headers/linux/fuse.h | 16 +- .../linux/input-event-codes.h | 3 + include/standard-headers/linux/pci_regs.h | 2 + include/standard-headers/linux/virtio_bt.h | 8 + include/standard-headers/linux/virtio_net.h | 4 + linux-headers/asm-arm64/kvm.h | 1 + linux-headers/asm-riscv/kvm.h | 3 + linux-headers/asm-x86/kvm.h | 11 +- linux-headers/linux/kvm.h | 34 ++--- linux-headers/linux/psci.h | 4 +- linux-headers/linux/vfio.h | 138 +++++++++++++++++- 13 files changed, 231 insertions(+), 40 deletions(-) diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index b868488f93..69cab17b38 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -743,6 +743,35 @@ extern "C" { */ #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) +/* + * Vivante TS (tile-status) buffer modifiers. They can be combined with all of + * the color buffer tiling modifiers defined above. When TS is present it's a + * separate buffer containing the clear/compression status of each tile. The + * modifiers are defined as VIVANTE_MOD_TS_c_s, where c is the color buffer + * tile size in bytes covered by one entry in the status buffer and s is the + * number of status bits per entry. + * We reserve the top 8 bits of the Vivante modifier space for tile status + * clear/compression modifiers, as future cores might add some more TS layout + * variations. + */ +#define VIVANTE_MOD_TS_64_4 (1ULL << 48) +#define VIVANTE_MOD_TS_64_2 (2ULL << 48) +#define VIVANTE_MOD_TS_128_4 (3ULL << 48) +#define VIVANTE_MOD_TS_256_4 (4ULL << 48) +#define VIVANTE_MOD_TS_MASK (0xfULL << 48) + +/* + * Vivante compression modifiers. Those depend on a TS modifier being present + * as the TS bits get reinterpreted as compression tags instead of simple + * clear markers when compression is enabled. + */ +#define VIVANTE_MOD_COMP_DEC400 (1ULL << 52) +#define VIVANTE_MOD_COMP_MASK (0xfULL << 52) + +/* Masking out the extension bits will yield the base modifier. */ +#define VIVANTE_MOD_EXT_MASK (VIVANTE_MOD_TS_MASK | \ + VIVANTE_MOD_COMP_MASK) + /* NVIDIA frame buffer modifiers */ /* diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 1dc56cdc0a..87176ab075 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -159,8 +159,10 @@ static inline uint32_t ethtool_cmd_speed(const struct ethtool_cmd *ep) * in its bus driver structure (e.g. pci_driver::name). Must * not be an empty string. * @version: Driver version string; may be an empty string - * @fw_version: Firmware version string; may be an empty string - * @erom_version: Expansion ROM version string; may be an empty string + * @fw_version: Firmware version string; driver defined; may be an + * empty string + * @erom_version: Expansion ROM version string; driver defined; may be + * an empty string * @bus_info: Device bus address. This should match the dev_name() * string for the underlying bus device, if there is one. May be * an empty string. @@ -179,10 +181,6 @@ static inline uint32_t ethtool_cmd_speed(const struct ethtool_cmd *ep) * * Users can use the %ETHTOOL_GSSET_INFO command to get the number of * strings in any string set (from Linux 2.6.34). - * - * Drivers should set at most @driver, @version, @fw_version and - * @bus_info in their get_drvinfo() implementation. The ethtool - * core fills in the other fields using other driver operations. */ struct ethtool_drvinfo { uint32_t cmd; @@ -1737,6 +1735,13 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, ETHTOOL_LINK_MODE_10baseT1L_Full_BIT = 92, + ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT = 93, + ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT = 94, + ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT = 95, + ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96, + ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97, + ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98, + /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; @@ -1848,6 +1853,7 @@ enum ethtool_link_mode_bit_indices { #define SPEED_100000 100000 #define SPEED_200000 200000 #define SPEED_400000 400000 +#define SPEED_800000 800000 #define SPEED_UNKNOWN -1 diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h index 713d259768..a1af78d989 100644 --- a/include/standard-headers/linux/fuse.h +++ b/include/standard-headers/linux/fuse.h @@ -197,6 +197,10 @@ * * 7.37 * - add FUSE_TMPFILE + * + * 7.38 + * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry + * - add FOPEN_PARALLEL_DIRECT_WRITES */ #ifndef _LINUX_FUSE_H @@ -228,7 +232,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 37 +#define FUSE_KERNEL_MINOR_VERSION 38 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -300,6 +304,7 @@ struct fuse_file_lock { * FOPEN_CACHE_DIR: allow caching this directory * FOPEN_STREAM: the file is stream-like (no file position at all) * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) + * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode */ #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) @@ -307,6 +312,7 @@ struct fuse_file_lock { #define FOPEN_CACHE_DIR (1 << 3) #define FOPEN_STREAM (1 << 4) #define FOPEN_NOFLUSH (1 << 5) +#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6) /** * INIT request/reply flags @@ -487,6 +493,12 @@ struct fuse_file_lock { */ #define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) +/** + * notify_inval_entry flags + * FUSE_EXPIRE_ONLY + */ +#define FUSE_EXPIRE_ONLY (1 << 0) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ @@ -915,7 +927,7 @@ struct fuse_notify_inval_inode_out { struct fuse_notify_inval_entry_out { uint64_t parent; uint32_t namelen; - uint32_t padding; + uint32_t flags; }; struct fuse_notify_delete_out { diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index 815f7a1dff..f6bab08540 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -614,6 +614,9 @@ #define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ #define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ #define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */ +#define KEY_CAMERA_ACCESS_ENABLE 0x24b /* Enables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_DISABLE 0x24c /* Disables programmatic access to camera devices. (HUTRR72) */ +#define KEY_CAMERA_ACCESS_TOGGLE 0x24d /* Toggles the current state of the camera access control. (HUTRR72) */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index 57b8e2ffb1..85ab127881 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -1058,6 +1058,7 @@ /* Precision Time Measurement */ #define PCI_PTM_CAP 0x04 /* PTM Capability */ #define PCI_PTM_CAP_REQ 0x00000001 /* Requester capable */ +#define PCI_PTM_CAP_RES 0x00000002 /* Responder capable */ #define PCI_PTM_CAP_ROOT 0x00000004 /* Root capable */ #define PCI_PTM_GRANULARITY_MASK 0x0000FF00 /* Clock granularity */ #define PCI_PTM_CTRL 0x08 /* PTM Control */ @@ -1119,6 +1120,7 @@ #define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */ #define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */ #define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */ +#define PCI_DOE_CAP_SIZEOF 0x18 /* Size of DOE register block */ /* DOE Data Object - note not actually registers */ #define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff diff --git a/include/standard-headers/linux/virtio_bt.h b/include/standard-headers/linux/virtio_bt.h index 245e1eff4b..a11ecc3f92 100644 --- a/include/standard-headers/linux/virtio_bt.h +++ b/include/standard-headers/linux/virtio_bt.h @@ -9,6 +9,7 @@ #define VIRTIO_BT_F_VND_HCI 0 /* Indicates vendor command support */ #define VIRTIO_BT_F_MSFT_EXT 1 /* Indicates MSFT vendor support */ #define VIRTIO_BT_F_AOSP_EXT 2 /* Indicates AOSP vendor support */ +#define VIRTIO_BT_F_CONFIG_V2 3 /* Use second version configuration */ enum virtio_bt_config_type { VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0, @@ -28,4 +29,11 @@ struct virtio_bt_config { uint16_t msft_opcode; } QEMU_PACKED; +struct virtio_bt_config_v2 { + uint8_t type; + uint8_t alignment; + uint16_t vendor; + uint16_t msft_opcode; +}; + #endif /* _LINUX_VIRTIO_BT_H */ diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h index 42c68caf71..c0e797067a 100644 --- a/include/standard-headers/linux/virtio_net.h +++ b/include/standard-headers/linux/virtio_net.h @@ -57,6 +57,9 @@ * Steering */ #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ #define VIRTIO_NET_F_NOTF_COAL 53 /* Device supports notifications coalescing */ +#define VIRTIO_NET_F_GUEST_USO4 54 /* Guest can handle USOv4 in. */ +#define VIRTIO_NET_F_GUEST_USO6 55 /* Guest can handle USOv6 in. */ +#define VIRTIO_NET_F_HOST_USO 56 /* Host can handle USO in. */ #define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */ #define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */ #define VIRTIO_NET_F_RSC_EXT 61 /* extended coalescing info */ @@ -130,6 +133,7 @@ struct virtio_net_hdr_v1 { #define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ #define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */ #define VIRTIO_NET_HDR_GSO_TCPV6 4 /* GSO frame, IPv6 TCP */ +#define VIRTIO_NET_HDR_GSO_UDP_L4 5 /* GSO frame, IPv4& IPv6 UDP (USO) */ #define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */ uint8_t gso_type; __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 4bf2d7246e..a7cfefb3a8 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -43,6 +43,7 @@ #define __KVM_HAVE_VCPU_EVENTS #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 +#define KVM_DIRTY_LOG_PAGE_OFFSET 64 #define KVM_REG_SIZE(id) \ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h index 8985ff234c..92af6f3f05 100644 --- a/linux-headers/asm-riscv/kvm.h +++ b/linux-headers/asm-riscv/kvm.h @@ -49,6 +49,9 @@ struct kvm_sregs { struct kvm_riscv_config { unsigned long isa; unsigned long zicbom_block_size; + unsigned long mvendorid; + unsigned long marchid; + unsigned long mimpid; }; /* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 46de10a809..2747d2ce14 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -53,14 +53,6 @@ /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 -struct kvm_memory_alias { - __u32 slot; /* this has a different namespace than memory slots */ - __u32 flags; - __u64 guest_phys_addr; - __u64 memory_size; - __u64 target_phys_addr; -}; - /* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */ struct kvm_pic_state { __u8 last_irr; /* edge detection */ @@ -214,6 +206,8 @@ struct kvm_msr_list { struct kvm_msr_filter_range { #define KVM_MSR_FILTER_READ (1 << 0) #define KVM_MSR_FILTER_WRITE (1 << 1) +#define KVM_MSR_FILTER_RANGE_VALID_MASK (KVM_MSR_FILTER_READ | \ + KVM_MSR_FILTER_WRITE) __u32 flags; __u32 nmsrs; /* number of msrs in bitmap */ __u32 base; /* MSR index the bitmap starts at */ @@ -224,6 +218,7 @@ struct kvm_msr_filter_range { struct kvm_msr_filter { #define KVM_MSR_FILTER_DEFAULT_ALLOW (0 << 0) #define KVM_MSR_FILTER_DEFAULT_DENY (1 << 0) +#define KVM_MSR_FILTER_VALID_MASK (KVM_MSR_FILTER_DEFAULT_DENY) __u32 flags; struct kvm_msr_filter_range ranges[KVM_MSR_FILTER_MAX_RANGES]; }; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index b2783c5202..1e2c16cfe3 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -86,14 +86,6 @@ struct kvm_debug_guest { /* *** End of deprecated interfaces *** */ -/* for KVM_CREATE_MEMORY_REGION */ -struct kvm_memory_region { - __u32 slot; - __u32 flags; - __u64 guest_phys_addr; - __u64 memory_size; /* bytes */ -}; - /* for KVM_SET_USER_MEMORY_REGION */ struct kvm_userspace_memory_region { __u32 slot; @@ -104,9 +96,9 @@ struct kvm_userspace_memory_region { }; /* - * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace, - * other bits are reserved for kvm internal use which are defined in - * include/linux/kvm_host.h. + * The bit 0 ~ bit 15 of kvm_userspace_memory_region::flags are visible for + * userspace, other bits are reserved for kvm internal use which are defined + * in include/linux/kvm_host.h. */ #define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) #define KVM_MEM_READONLY (1UL << 1) @@ -483,6 +475,9 @@ struct kvm_run { #define KVM_MSR_EXIT_REASON_INVAL (1 << 0) #define KVM_MSR_EXIT_REASON_UNKNOWN (1 << 1) #define KVM_MSR_EXIT_REASON_FILTER (1 << 2) +#define KVM_MSR_EXIT_REASON_VALID_MASK (KVM_MSR_EXIT_REASON_INVAL | \ + KVM_MSR_EXIT_REASON_UNKNOWN | \ + KVM_MSR_EXIT_REASON_FILTER) __u32 reason; /* kernel -> user */ __u32 index; /* kernel -> user */ __u64 data; /* kernel <-> user */ @@ -1176,6 +1171,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_ZPCI_OP 221 #define KVM_CAP_S390_CPU_TOPOLOGY 222 #define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223 +#define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224 +#define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225 #ifdef KVM_CAP_IRQ_ROUTING @@ -1265,6 +1262,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) #define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) +#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) struct kvm_xen_hvm_config { __u32 flags; @@ -1435,18 +1433,12 @@ struct kvm_vfio_spapr_tce { __s32 tablefd; }; -/* - * ioctls for VM fds - */ -#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) /* * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns * a vcpu fd. */ #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) -/* KVM_SET_MEMORY_ALIAS is obsolete: */ -#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) #define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44) #define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45) #define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \ @@ -1738,6 +1730,8 @@ enum pv_cmd_id { KVM_PV_UNSHARE_ALL, KVM_PV_INFO, KVM_PV_DUMP, + KVM_PV_ASYNC_CLEANUP_PREPARE, + KVM_PV_ASYNC_CLEANUP_PERFORM, }; struct kvm_pv_cmd { @@ -1768,8 +1762,10 @@ struct kvm_xen_hvm_attr { union { __u8 long_mode; __u8 vector; + __u8 runstate_update_flag; struct { __u64 gfn; +#define KVM_XEN_INVALID_GFN ((__u64)-1) } shared_info; struct { __u32 send_port; @@ -1801,6 +1797,7 @@ struct kvm_xen_hvm_attr { } u; }; + /* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ #define KVM_XEN_ATTR_TYPE_LONG_MODE 0x0 #define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x1 @@ -1808,6 +1805,8 @@ struct kvm_xen_hvm_attr { /* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */ #define KVM_XEN_ATTR_TYPE_EVTCHN 0x3 #define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4 +/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */ +#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5 /* Per-vCPU Xen attributes */ #define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr) @@ -1824,6 +1823,7 @@ struct kvm_xen_vcpu_attr { __u16 pad[3]; union { __u64 gpa; +#define KVM_XEN_INVALID_GPA ((__u64)-1) __u64 pad[8]; struct { __u64 state; diff --git a/linux-headers/linux/psci.h b/linux-headers/linux/psci.h index e60dfd8907..74f3cb5007 100644 --- a/linux-headers/linux/psci.h +++ b/linux-headers/linux/psci.h @@ -58,7 +58,7 @@ #define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_0_2_FN(18) #define PSCI_1_1_FN_MEM_PROTECT PSCI_0_2_FN(19) -#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN(19) +#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN(20) #define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND PSCI_0_2_FN64(12) #define PSCI_1_0_FN64_NODE_HW_STATE PSCI_0_2_FN64(13) @@ -67,7 +67,7 @@ #define PSCI_1_0_FN64_STAT_COUNT PSCI_0_2_FN64(17) #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18) -#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN64(19) +#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE PSCI_0_2_FN64(20) /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index bee7e42198..c59692ce0b 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -819,12 +819,20 @@ struct vfio_device_feature { * VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P means that RUNNING_P2P * is supported in addition to the STOP_COPY states. * + * VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY means that + * PRE_COPY is supported in addition to the STOP_COPY states. + * + * VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P | VFIO_MIGRATION_PRE_COPY + * means that RUNNING_P2P, PRE_COPY and PRE_COPY_P2P are supported + * in addition to the STOP_COPY states. + * * Other combinations of flags have behavior to be defined in the future. */ struct vfio_device_feature_migration { __aligned_u64 flags; #define VFIO_MIGRATION_STOP_COPY (1 << 0) #define VFIO_MIGRATION_P2P (1 << 1) +#define VFIO_MIGRATION_PRE_COPY (1 << 2) }; #define VFIO_DEVICE_FEATURE_MIGRATION 1 @@ -875,8 +883,13 @@ struct vfio_device_feature_mig_state { * RESUMING - The device is stopped and is loading a new internal state * ERROR - The device has failed and must be reset * - * And 1 optional state to support VFIO_MIGRATION_P2P: + * And optional states to support VFIO_MIGRATION_P2P: * RUNNING_P2P - RUNNING, except the device cannot do peer to peer DMA + * And VFIO_MIGRATION_PRE_COPY: + * PRE_COPY - The device is running normally but tracking internal state + * changes + * And VFIO_MIGRATION_P2P | VFIO_MIGRATION_PRE_COPY: + * PRE_COPY_P2P - PRE_COPY, except the device cannot do peer to peer DMA * * The FSM takes actions on the arcs between FSM states. The driver implements * the following behavior for the FSM arcs: @@ -908,20 +921,48 @@ struct vfio_device_feature_mig_state { * * To abort a RESUMING session the device must be reset. * + * PRE_COPY -> RUNNING * RUNNING_P2P -> RUNNING * While in RUNNING the device is fully operational, the device may generate * interrupts, DMA, respond to MMIO, all vfio device regions are functional, * and the device may advance its internal state. * + * The PRE_COPY arc will terminate a data transfer session. + * + * PRE_COPY_P2P -> RUNNING_P2P * RUNNING -> RUNNING_P2P * STOP -> RUNNING_P2P * While in RUNNING_P2P the device is partially running in the P2P quiescent * state defined below. * - * STOP -> STOP_COPY - * This arc begin the process of saving the device state and will return a - * new data_fd. + * The PRE_COPY_P2P arc will terminate a data transfer session. * + * RUNNING -> PRE_COPY + * RUNNING_P2P -> PRE_COPY_P2P + * STOP -> STOP_COPY + * PRE_COPY, PRE_COPY_P2P and STOP_COPY form the "saving group" of states + * which share a data transfer session. Moving between these states alters + * what is streamed in session, but does not terminate or otherwise affect + * the associated fd. + * + * These arcs begin the process of saving the device state and will return a + * new data_fd. The migration driver may perform actions such as enabling + * dirty logging of device state when entering PRE_COPY or PER_COPY_P2P. + * + * Each arc does not change the device operation, the device remains + * RUNNING, P2P quiesced or in STOP. The STOP_COPY state is described below + * in PRE_COPY_P2P -> STOP_COPY. + * + * PRE_COPY -> PRE_COPY_P2P + * Entering PRE_COPY_P2P continues all the behaviors of PRE_COPY above. + * However, while in the PRE_COPY_P2P state, the device is partially running + * in the P2P quiescent state defined below, like RUNNING_P2P. + * + * PRE_COPY_P2P -> PRE_COPY + * This arc allows returning the device to a full RUNNING behavior while + * continuing all the behaviors of PRE_COPY. + * + * PRE_COPY_P2P -> STOP_COPY * While in the STOP_COPY state the device has the same behavior as STOP * with the addition that the data transfers session continues to stream the * migration state. End of stream on the FD indicates the entire device @@ -939,6 +980,13 @@ struct vfio_device_feature_mig_state { * device state for this arc if required to prepare the device to receive the * migration data. * + * STOP_COPY -> PRE_COPY + * STOP_COPY -> PRE_COPY_P2P + * These arcs are not permitted and return error if requested. Future + * revisions of this API may define behaviors for these arcs, in this case + * support will be discoverable by a new flag in + * VFIO_DEVICE_FEATURE_MIGRATION. + * * any -> ERROR * ERROR cannot be specified as a device state, however any transition request * can be failed with an errno return and may then move the device_state into @@ -950,7 +998,7 @@ struct vfio_device_feature_mig_state { * The optional peer to peer (P2P) quiescent state is intended to be a quiescent * state for the device for the purposes of managing multiple devices within a * user context where peer-to-peer DMA between devices may be active. The - * RUNNING_P2P states must prevent the device from initiating + * RUNNING_P2P and PRE_COPY_P2P states must prevent the device from initiating * any new P2P DMA transactions. If the device can identify P2P transactions * then it can stop only P2P DMA, otherwise it must stop all DMA. The migration * driver must complete any such outstanding operations prior to completing the @@ -963,6 +1011,8 @@ struct vfio_device_feature_mig_state { * above FSM arcs. As there are multiple paths through the FSM arcs the path * should be selected based on the following rules: * - Select the shortest path. + * - The path cannot have saving group states as interior arcs, only + * starting/end states. * Refer to vfio_mig_get_next_state() for the result of the algorithm. * * The automatic transit through the FSM arcs that make up the combination @@ -976,6 +1026,9 @@ struct vfio_device_feature_mig_state { * support them. The user can discover if these states are supported by using * VFIO_DEVICE_FEATURE_MIGRATION. By using combination transitions the user can * avoid knowing about these optional states if the kernel driver supports them. + * + * Arcs touching PRE_COPY and PRE_COPY_P2P are removed if support for PRE_COPY + * is not present. */ enum vfio_device_mig_state { VFIO_DEVICE_STATE_ERROR = 0, @@ -984,8 +1037,70 @@ enum vfio_device_mig_state { VFIO_DEVICE_STATE_STOP_COPY = 3, VFIO_DEVICE_STATE_RESUMING = 4, VFIO_DEVICE_STATE_RUNNING_P2P = 5, + VFIO_DEVICE_STATE_PRE_COPY = 6, + VFIO_DEVICE_STATE_PRE_COPY_P2P = 7, }; +/** + * VFIO_MIG_GET_PRECOPY_INFO - _IO(VFIO_TYPE, VFIO_BASE + 21) + * + * This ioctl is used on the migration data FD in the precopy phase of the + * migration data transfer. It returns an estimate of the current data sizes + * remaining to be transferred. It allows the user to judge when it is + * appropriate to leave PRE_COPY for STOP_COPY. + * + * This ioctl is valid only in PRE_COPY states and kernel driver should + * return -EINVAL from any other migration state. + * + * The vfio_precopy_info data structure returned by this ioctl provides + * estimates of data available from the device during the PRE_COPY states. + * This estimate is split into two categories, initial_bytes and + * dirty_bytes. + * + * The initial_bytes field indicates the amount of initial precopy + * data available from the device. This field should have a non-zero initial + * value and decrease as migration data is read from the device. + * It is recommended to leave PRE_COPY for STOP_COPY only after this field + * reaches zero. Leaving PRE_COPY earlier might make things slower. + * + * The dirty_bytes field tracks device state changes relative to data + * previously retrieved. This field starts at zero and may increase as + * the internal device state is modified or decrease as that modified + * state is read from the device. + * + * Userspace may use the combination of these fields to estimate the + * potential data size available during the PRE_COPY phases, as well as + * trends relative to the rate the device is dirtying its internal + * state, but these fields are not required to have any bearing relative + * to the data size available during the STOP_COPY phase. + * + * Drivers have a lot of flexibility in when and what they transfer during the + * PRE_COPY phase, and how they report this from VFIO_MIG_GET_PRECOPY_INFO. + * + * During pre-copy the migration data FD has a temporary "end of stream" that is + * reached when both initial_bytes and dirty_byte are zero. For instance, this + * may indicate that the device is idle and not currently dirtying any internal + * state. When read() is done on this temporary end of stream the kernel driver + * should return ENOMSG from read(). Userspace can wait for more data (which may + * never come) by using poll. + * + * Once in STOP_COPY the migration data FD has a permanent end of stream + * signaled in the usual way by read() always returning 0 and poll always + * returning readable. ENOMSG may not be returned in STOP_COPY. + * Support for this ioctl is mandatory if a driver claims to support + * VFIO_MIGRATION_PRE_COPY. + * + * Return: 0 on success, -1 and errno set on failure. + */ +struct vfio_precopy_info { + __u32 argsz; + __u32 flags; + __aligned_u64 initial_bytes; + __aligned_u64 dirty_bytes; +}; + +#define VFIO_MIG_GET_PRECOPY_INFO _IO(VFIO_TYPE, VFIO_BASE + 21) + /* * Upon VFIO_DEVICE_FEATURE_SET, allow the device to be moved into a low power * state with the platform-based power management. Device use of lower power @@ -1128,6 +1243,19 @@ struct vfio_device_feature_dma_logging_report { #define VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT 8 +/* + * Upon VFIO_DEVICE_FEATURE_GET read back the estimated data length that will + * be required to complete stop copy. + * + * Note: Can be called on each device state. + */ + +struct vfio_device_feature_mig_data_size { + __aligned_u64 stop_copy_length; +}; + +#define VFIO_DEVICE_FEATURE_MIG_DATA_SIZE 9 + /* -------- API for Type1 VFIO IOMMU -------- */ /** From 5c4dbcb7489463b8862d3e4fa2490f5fd3d683fe Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:21 +0200 Subject: [PATCH 763/814] vfio/migration: Fix NULL pointer dereference bug As part of its error flow, vfio_vmstate_change() accesses MigrationState->to_dst_file without any checks. This can cause a NULL pointer dereference if the error flow is taken and MigrationState->to_dst_file is not set. For example, this can happen if VM is started or stopped not during migration and vfio_vmstate_change() error flow is taken, as MigrationState->to_dst_file is not set at that time. Fix it by checking that MigrationState->to_dst_file is set before using it. Fixes: 02a7e71b1e5b ("vfio: Add VM state change handler to know state of VM") Signed-off-by: Avihai Horon Reviewed-by: Juan Quintela Reviewed-by: Vladimir Sementsov-Ogievskiy Link: https://lore.kernel.org/r/20230216143630.25610-3-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/migration.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 83d2d44080..65f3f3bef7 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -741,7 +741,9 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) */ error_report("%s: Failed to set device state 0x%x", vbasedev->name, (migration->device_state & mask) | value); - qemu_file_set_error(migrate_get_current()->to_dst_file, ret); + if (migrate_get_current()->to_dst_file) { + qemu_file_set_error(migrate_get_current()->to_dst_file, ret); + } } vbasedev->migration->vm_running = running; trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), From b051a3f640e2efc95e9e23c5cb1bb5a4c07731e2 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:22 +0200 Subject: [PATCH 764/814] vfio/migration: Allow migration without VFIO IOMMU dirty tracking support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, if IOMMU of a VFIO container doesn't support dirty page tracking, migration is blocked. This is because a DMA-able VFIO device can dirty RAM pages without updating QEMU about it, thus breaking the migration. However, this doesn't mean that migration can't be done at all. In such case, allow migration and let QEMU VFIO code mark all pages dirty. This guarantees that all pages that might have gotten dirty are reported back, and thus guarantees a valid migration even without VFIO IOMMU dirty tracking support. The motivation for this patch is the introduction of iommufd [1]. iommufd can directly implement the /dev/vfio/vfio container IOCTLs by mapping them into its internal ops, allowing the usage of these IOCTLs over iommufd. However, VFIO IOMMU dirty tracking is not supported by this VFIO compatibility API. This patch will allow migration by hosts that use the VFIO compatibility API and prevent migration regressions caused by the lack of VFIO IOMMU dirty tracking support. [1] https://lore.kernel.org/kvm/0-v6-a196d26f289e+11787-iommufd_jgg@nvidia.com/ Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-4-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 20 ++++++++++++++++++-- hw/vfio/migration.c | 3 +-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 130e5d1dc7..f6dd571549 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -488,6 +488,12 @@ static int vfio_dma_unmap(VFIOContainer *container, return -errno; } + if (iotlb && vfio_devices_all_running_and_saving(container)) { + cpu_physical_memory_set_dirty_range(iotlb->translated_addr, size, + tcg_enabled() ? DIRTY_CLIENTS_ALL : + DIRTY_CLIENTS_NOCODE); + } + return 0; } @@ -1201,6 +1207,10 @@ static void vfio_set_dirty_page_tracking(VFIOContainer *container, bool start) .argsz = sizeof(dirty), }; + if (!container->dirty_pages_supported) { + return; + } + if (start) { dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; } else { @@ -1236,6 +1246,13 @@ static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, uint64_t pages; int ret; + if (!container->dirty_pages_supported) { + cpu_physical_memory_set_dirty_range(ram_addr, size, + tcg_enabled() ? DIRTY_CLIENTS_ALL : + DIRTY_CLIENTS_NOCODE); + return 0; + } + dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); @@ -1409,8 +1426,7 @@ static void vfio_listener_log_sync(MemoryListener *listener, { VFIOContainer *container = container_of(listener, VFIOContainer, listener); - if (vfio_listener_skipped_section(section) || - !container->dirty_pages_supported) { + if (vfio_listener_skipped_section(section)) { return; } diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 65f3f3bef7..e56eef1ee8 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -858,11 +858,10 @@ int64_t vfio_mig_bytes_transferred(void) int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) { - VFIOContainer *container = vbasedev->group->container; struct vfio_region_info *info = NULL; int ret = -ENOTSUP; - if (!vbasedev->enable_migration || !container->dirty_pages_supported) { + if (!vbasedev->enable_migration) { goto add_blocker; } From 8b942af393a2d9f822aea4e5e0d241e668146bf2 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:23 +0200 Subject: [PATCH 765/814] vfio/common: Change vfio_devices_all_running_and_saving() logic to equivalent one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_devices_all_running_and_saving() is used to check if migration is in pre-copy phase. This is done by checking if migration is in setup or active states and if all VFIO devices are in pre-copy state, i.e. _SAVING | _RUNNING. In VFIO migration protocol v2 pre-copy support is made optional. Hence, a matching v2 protocol pre-copy state can't be used here. As preparation for adding v2 protocol, change vfio_devices_all_running_and_saving() logic such that it doesn't use the VFIO pre-copy state. The new equivalent logic checks if migration is in active state and if all VFIO devices are in running state [1]. No functional changes intended. [1] Note that checking if migration is in setup or active states and if all VFIO devices are in running state doesn't guarantee that we are in pre-copy phase, thus we check if migration is only in active state. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-5-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index f6dd571549..3a35f4afad 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -40,6 +40,7 @@ #include "trace.h" #include "qapi/error.h" #include "migration/migration.h" +#include "migration/misc.h" #include "sysemu/tpm.h" VFIOGroupList vfio_group_list = @@ -363,13 +364,16 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return true; } -static bool vfio_devices_all_running_and_saving(VFIOContainer *container) +/* + * Check if all VFIO devices are running and migration is active, which is + * essentially equivalent to the migration being in pre-copy phase. + */ +static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) { VFIOGroup *group; VFIODevice *vbasedev; - MigrationState *ms = migrate_get_current(); - if (!migration_is_setup_or_active(ms->state)) { + if (!migration_is_active(migrate_get_current())) { return false; } @@ -381,8 +385,7 @@ static bool vfio_devices_all_running_and_saving(VFIOContainer *container) return false; } - if ((migration->device_state & VFIO_DEVICE_STATE_V1_SAVING) && - (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { + if (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING) { continue; } else { return false; @@ -461,7 +464,7 @@ static int vfio_dma_unmap(VFIOContainer *container, }; if (iotlb && container->dirty_pages_supported && - vfio_devices_all_running_and_saving(container)) { + vfio_devices_all_running_and_mig_active(container)) { return vfio_dma_unmap_bitmap(container, iova, size, iotlb); } @@ -488,7 +491,7 @@ static int vfio_dma_unmap(VFIOContainer *container, return -errno; } - if (iotlb && vfio_devices_all_running_and_saving(container)) { + if (iotlb && vfio_devices_all_running_and_mig_active(container)) { cpu_physical_memory_set_dirty_range(iotlb->translated_addr, size, tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE); From 29d81b71aa2ac0f594d881460e22e291a9417a74 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:24 +0200 Subject: [PATCH 766/814] vfio/migration: Block multiple devices migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently VFIO migration doesn't implement some kind of intermediate quiescent state in which P2P DMAs are quiesced before stopping or running the device. This can cause problems in multi-device migration where the devices are doing P2P DMAs, since the devices are not stopped together at the same time. Until such support is added, block migration of multiple devices. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-6-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 53 +++++++++++++++++++++++++++++++++++ hw/vfio/migration.c | 6 ++++ include/hw/vfio/vfio-common.h | 2 ++ 3 files changed, 61 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 3a35f4afad..fe80ccf914 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -41,6 +41,7 @@ #include "qapi/error.h" #include "migration/migration.h" #include "migration/misc.h" +#include "migration/blocker.h" #include "sysemu/tpm.h" VFIOGroupList vfio_group_list = @@ -337,6 +338,58 @@ bool vfio_mig_active(void) return true; } +static Error *multiple_devices_migration_blocker; + +static unsigned int vfio_migratable_device_num(void) +{ + VFIOGroup *group; + VFIODevice *vbasedev; + unsigned int device_num = 0; + + QLIST_FOREACH(group, &vfio_group_list, next) { + QLIST_FOREACH(vbasedev, &group->device_list, next) { + if (vbasedev->migration) { + device_num++; + } + } + } + + return device_num; +} + +int vfio_block_multiple_devices_migration(Error **errp) +{ + int ret; + + if (multiple_devices_migration_blocker || + vfio_migratable_device_num() <= 1) { + return 0; + } + + error_setg(&multiple_devices_migration_blocker, + "Migration is currently not supported with multiple " + "VFIO devices"); + ret = migrate_add_blocker(multiple_devices_migration_blocker, errp); + if (ret < 0) { + error_free(multiple_devices_migration_blocker); + multiple_devices_migration_blocker = NULL; + } + + return ret; +} + +void vfio_unblock_multiple_devices_migration(void) +{ + if (!multiple_devices_migration_blocker || + vfio_migratable_device_num() > 1) { + return; + } + + migrate_del_blocker(multiple_devices_migration_blocker); + error_free(multiple_devices_migration_blocker); + multiple_devices_migration_blocker = NULL; +} + static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) { VFIOGroup *group; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index e56eef1ee8..8e96999669 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -878,6 +878,11 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) goto add_blocker; } + ret = vfio_block_multiple_devices_migration(errp); + if (ret) { + return ret; + } + trace_vfio_migration_probe(vbasedev->name, info->index); g_free(info); return 0; @@ -904,6 +909,7 @@ void vfio_migration_finalize(VFIODevice *vbasedev) qemu_del_vm_change_state_handler(migration->vm_state); unregister_savevm(VMSTATE_IF(vbasedev->dev), "vfio", vbasedev); vfio_migration_exit(vbasedev); + vfio_unblock_multiple_devices_migration(); } if (vbasedev->migration_blocker) { diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index e573f5a9f1..56b1683824 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -218,6 +218,8 @@ typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; extern VFIOGroupList vfio_group_list; bool vfio_mig_active(void); +int vfio_block_multiple_devices_migration(Error **errp); +void vfio_unblock_multiple_devices_migration(void); int64_t vfio_mig_bytes_transferred(void); #ifdef CONFIG_LINUX From 16fe4e8ab7588896f67ffc8a1d0dc1b0c698b064 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:25 +0200 Subject: [PATCH 767/814] vfio/migration: Move migration v1 logic to vfio_migration_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move vfio_dev_get_region_info() logic from vfio_migration_probe() to vfio_migration_init(). This logic is specific to v1 protocol and moving it will make it easier to add the v2 protocol implementation later. No functional changes intended. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-7-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/migration.c | 30 +++++++++++++++--------------- hw/vfio/trace-events | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 8e96999669..a3bf7327a1 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -786,14 +786,14 @@ static void vfio_migration_exit(VFIODevice *vbasedev) vbasedev->migration = NULL; } -static int vfio_migration_init(VFIODevice *vbasedev, - struct vfio_region_info *info) +static int vfio_migration_init(VFIODevice *vbasedev) { int ret; Object *obj; VFIOMigration *migration; char id[256] = ""; g_autofree char *path = NULL, *oid = NULL; + struct vfio_region_info *info; if (!vbasedev->ops->vfio_get_object) { return -EINVAL; @@ -804,6 +804,14 @@ static int vfio_migration_init(VFIODevice *vbasedev, return -EINVAL; } + ret = vfio_get_dev_region_info(vbasedev, + VFIO_REGION_TYPE_MIGRATION_DEPRECATED, + VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, + &info); + if (ret) { + return ret; + } + vbasedev->migration = g_new0(VFIOMigration, 1); vbasedev->migration->device_state = VFIO_DEVICE_STATE_V1_RUNNING; vbasedev->migration->vm_running = runstate_is_running(); @@ -823,6 +831,8 @@ static int vfio_migration_init(VFIODevice *vbasedev, goto err; } + g_free(info); + migration = vbasedev->migration; migration->vbasedev = vbasedev; @@ -845,6 +855,7 @@ static int vfio_migration_init(VFIODevice *vbasedev, return 0; err: + g_free(info); vfio_migration_exit(vbasedev); return ret; } @@ -858,22 +869,13 @@ int64_t vfio_mig_bytes_transferred(void) int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) { - struct vfio_region_info *info = NULL; int ret = -ENOTSUP; if (!vbasedev->enable_migration) { goto add_blocker; } - ret = vfio_get_dev_region_info(vbasedev, - VFIO_REGION_TYPE_MIGRATION_DEPRECATED, - VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, - &info); - if (ret) { - goto add_blocker; - } - - ret = vfio_migration_init(vbasedev, info); + ret = vfio_migration_init(vbasedev); if (ret) { goto add_blocker; } @@ -883,14 +885,12 @@ int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) return ret; } - trace_vfio_migration_probe(vbasedev->name, info->index); - g_free(info); + trace_vfio_migration_probe(vbasedev->name); return 0; add_blocker: error_setg(&vbasedev->migration_blocker, "VFIO device doesn't support migration"); - g_free(info); ret = migrate_add_blocker(vbasedev->migration_blocker, errp); if (ret < 0) { diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 90a8aecb37..6be5381cc9 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -148,7 +148,7 @@ vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u" vfio_display_edid_write_error(void) "" # migration.c -vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" +vfio_migration_probe(const char *name) " (%s)" vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" From 6eeb2909104664af4c3488232f3c3cd8471c38c3 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:26 +0200 Subject: [PATCH 768/814] vfio/migration: Rename functions/structs related to v1 protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid name collisions, rename functions and structs related to VFIO migration protocol v1. This will allow the two protocols to co-exist when v2 protocol is added, until v1 is removed. No functional changes intended. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-8-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 6 +- hw/vfio/migration.c | 102 +++++++++++++++++----------------- hw/vfio/trace-events | 12 ++-- include/hw/vfio/vfio-common.h | 2 +- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index fe80ccf914..1c974e9c5a 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -408,8 +408,8 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return false; } - if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) - && (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING)) { + if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) && + (migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING)) { return false; } } @@ -438,7 +438,7 @@ static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) return false; } - if (migration->device_state & VFIO_DEVICE_STATE_V1_RUNNING) { + if (migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING) { continue; } else { return false; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index a3bf7327a1..a5fe285721 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -107,8 +107,8 @@ static int vfio_mig_rw(VFIODevice *vbasedev, __u8 *buf, size_t count, * an error is returned. */ -static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, - uint32_t value) +static int vfio_migration_v1_set_state(VFIODevice *vbasedev, uint32_t mask, + uint32_t value) { VFIOMigration *migration = vbasedev->migration; VFIORegion *region = &migration->region; @@ -145,8 +145,8 @@ static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, return ret; } - migration->device_state = device_state; - trace_vfio_migration_set_state(vbasedev->name, device_state); + migration->device_state_v1 = device_state; + trace_vfio_migration_v1_set_state(vbasedev->name, device_state); return 0; } @@ -260,8 +260,8 @@ static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) return ret; } -static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, - uint64_t data_size) +static int vfio_v1_load_buffer(QEMUFile *f, VFIODevice *vbasedev, + uint64_t data_size) { VFIORegion *region = &vbasedev->migration->region; uint64_t data_offset = 0, size, report_size; @@ -288,7 +288,7 @@ static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, data_size = 0; } - trace_vfio_load_state_device_data(vbasedev->name, data_offset, size); + trace_vfio_v1_load_state_device_data(vbasedev->name, data_offset, size); while (size) { void *buf; @@ -394,7 +394,7 @@ static int vfio_load_device_config_state(QEMUFile *f, void *opaque) return qemu_file_get_error(f); } -static void vfio_migration_cleanup(VFIODevice *vbasedev) +static void vfio_migration_v1_cleanup(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; @@ -405,13 +405,13 @@ static void vfio_migration_cleanup(VFIODevice *vbasedev) /* ---------------------------------------------------------------------- */ -static int vfio_save_setup(QEMUFile *f, void *opaque) +static int vfio_v1_save_setup(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; int ret; - trace_vfio_save_setup(vbasedev->name); + trace_vfio_v1_save_setup(vbasedev->name); qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE); @@ -431,8 +431,8 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) } } - ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_V1_SAVING); + ret = vfio_migration_v1_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state SAVING", vbasedev->name); return ret; @@ -448,16 +448,16 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) return 0; } -static void vfio_save_cleanup(void *opaque) +static void vfio_v1_save_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; - vfio_migration_cleanup(vbasedev); + vfio_migration_v1_cleanup(vbasedev); trace_vfio_save_cleanup(vbasedev->name); } -static void vfio_state_pending(void *opaque, uint64_t *must_precopy, - uint64_t *can_postcopy) +static void vfio_v1_state_pending(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; @@ -470,7 +470,7 @@ static void vfio_state_pending(void *opaque, uint64_t *must_precopy, *must_precopy += migration->pending_bytes; - trace_vfio_state_pending(vbasedev->name, *must_precopy, *can_postcopy); + trace_vfio_v1_state_pending(vbasedev->name, *must_precopy, *can_postcopy); } static int vfio_save_iterate(QEMUFile *f, void *opaque) @@ -520,15 +520,15 @@ static int vfio_save_iterate(QEMUFile *f, void *opaque) return 0; } -static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) +static int vfio_v1_save_complete_precopy(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; uint64_t data_size; int ret; - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_RUNNING, - VFIO_DEVICE_STATE_V1_SAVING); + ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_RUNNING, + VFIO_DEVICE_STATE_V1_SAVING); if (ret) { error_report("%s: Failed to set state STOP and SAVING", vbasedev->name); @@ -565,13 +565,14 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) return ret; } - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_SAVING, 0); + ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_SAVING, + 0); if (ret) { error_report("%s: Failed to set state STOPPED", vbasedev->name); return ret; } - trace_vfio_save_complete_precopy(vbasedev->name); + trace_vfio_v1_save_complete_precopy(vbasedev->name); return ret; } @@ -588,7 +589,7 @@ static void vfio_save_state(QEMUFile *f, void *opaque) } } -static int vfio_load_setup(QEMUFile *f, void *opaque) +static int vfio_v1_load_setup(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; @@ -604,8 +605,8 @@ static int vfio_load_setup(QEMUFile *f, void *opaque) } } - ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_V1_RESUMING); + ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, + VFIO_DEVICE_STATE_V1_RESUMING); if (ret) { error_report("%s: Failed to set state RESUMING", vbasedev->name); if (migration->region.mmaps) { @@ -615,11 +616,11 @@ static int vfio_load_setup(QEMUFile *f, void *opaque) return ret; } -static int vfio_load_cleanup(void *opaque) +static int vfio_v1_load_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; - vfio_migration_cleanup(vbasedev); + vfio_migration_v1_cleanup(vbasedev); trace_vfio_load_cleanup(vbasedev->name); return 0; } @@ -657,7 +658,7 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) uint64_t data_size = qemu_get_be64(f); if (data_size) { - ret = vfio_load_buffer(f, vbasedev, data_size); + ret = vfio_v1_load_buffer(f, vbasedev, data_size); if (ret < 0) { return ret; } @@ -678,22 +679,22 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) return ret; } -static SaveVMHandlers savevm_vfio_handlers = { - .save_setup = vfio_save_setup, - .save_cleanup = vfio_save_cleanup, - .state_pending_exact = vfio_state_pending, - .state_pending_estimate = vfio_state_pending, +static SaveVMHandlers savevm_vfio_v1_handlers = { + .save_setup = vfio_v1_save_setup, + .save_cleanup = vfio_v1_save_cleanup, + .state_pending_exact = vfio_v1_state_pending, + .state_pending_estimate = vfio_v1_state_pending, .save_live_iterate = vfio_save_iterate, - .save_live_complete_precopy = vfio_save_complete_precopy, + .save_live_complete_precopy = vfio_v1_save_complete_precopy, .save_state = vfio_save_state, - .load_setup = vfio_load_setup, - .load_cleanup = vfio_load_cleanup, + .load_setup = vfio_v1_load_setup, + .load_cleanup = vfio_v1_load_cleanup, .load_state = vfio_load_state, }; /* ---------------------------------------------------------------------- */ -static void vfio_vmstate_change(void *opaque, bool running, RunState state) +static void vfio_v1_vmstate_change(void *opaque, bool running, RunState state) { VFIODevice *vbasedev = opaque; VFIOMigration *migration = vbasedev->migration; @@ -733,21 +734,21 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) } } - ret = vfio_migration_set_state(vbasedev, mask, value); + ret = vfio_migration_v1_set_state(vbasedev, mask, value); if (ret) { /* * Migration should be aborted in this case, but vm_state_notify() * currently does not support reporting failures. */ error_report("%s: Failed to set device state 0x%x", vbasedev->name, - (migration->device_state & mask) | value); + (migration->device_state_v1 & mask) | value); if (migrate_get_current()->to_dst_file) { qemu_file_set_error(migrate_get_current()->to_dst_file, ret); } } vbasedev->migration->vm_running = running; - trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), - (migration->device_state & mask) | value); + trace_vfio_v1_vmstate_change(vbasedev->name, running, RunState_str(state), + (migration->device_state_v1 & mask) | value); } static void vfio_migration_state_notifier(Notifier *notifier, void *data) @@ -766,10 +767,10 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) case MIGRATION_STATUS_CANCELLED: case MIGRATION_STATUS_FAILED: bytes_transferred = 0; - ret = vfio_migration_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_V1_SAVING | - VFIO_DEVICE_STATE_V1_RESUMING), - VFIO_DEVICE_STATE_V1_RUNNING); + ret = vfio_migration_v1_set_state(vbasedev, + ~(VFIO_DEVICE_STATE_V1_SAVING | + VFIO_DEVICE_STATE_V1_RESUMING), + VFIO_DEVICE_STATE_V1_RUNNING); if (ret) { error_report("%s: Failed to set state RUNNING", vbasedev->name); } @@ -813,7 +814,7 @@ static int vfio_migration_init(VFIODevice *vbasedev) } vbasedev->migration = g_new0(VFIOMigration, 1); - vbasedev->migration->device_state = VFIO_DEVICE_STATE_V1_RUNNING; + vbasedev->migration->device_state_v1 = VFIO_DEVICE_STATE_V1_RUNNING; vbasedev->migration->vm_running = runstate_is_running(); ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, @@ -844,12 +845,11 @@ static int vfio_migration_init(VFIODevice *vbasedev) } strpadcpy(id, sizeof(id), path, '\0'); - register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, &savevm_vfio_handlers, - vbasedev); + register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, + &savevm_vfio_v1_handlers, vbasedev); - migration->vm_state = qdev_add_vm_change_state_handler(vbasedev->dev, - vfio_vmstate_change, - vbasedev); + migration->vm_state = qdev_add_vm_change_state_handler( + vbasedev->dev, vfio_v1_vmstate_change, vbasedev); migration->migration_state.notify = vfio_migration_state_notifier; add_migration_state_change_notifier(&migration->migration_state); return 0; diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 6be5381cc9..c8739449df 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -149,20 +149,20 @@ vfio_display_edid_write_error(void) "" # migration.c vfio_migration_probe(const char *name) " (%s)" -vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" -vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" +vfio_migration_v1_set_state(const char *name, uint32_t state) " (%s) state %d" +vfio_v1_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" -vfio_save_setup(const char *name) " (%s)" +vfio_v1_save_setup(const char *name) " (%s)" vfio_save_cleanup(const char *name) " (%s)" vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 vfio_save_device_config_state(const char *name) " (%s)" -vfio_state_pending(const char *name, uint64_t precopy, uint64_t postcopy) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64 +vfio_v1_state_pending(const char *name, uint64_t precopy, uint64_t postcopy) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64 vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" -vfio_save_complete_precopy(const char *name) " (%s)" +vfio_v1_save_complete_precopy(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 -vfio_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 +vfio_v1_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 vfio_load_cleanup(const char *name) " (%s)" vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 56b1683824..2c0fb1d622 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -62,7 +62,7 @@ typedef struct VFIOMigration { struct VFIODevice *vbasedev; VMChangeStateEntry *vm_state; VFIORegion region; - uint32_t device_state; + uint32_t device_state_v1; int vm_running; Notifier migration_state; uint64_t pending_bytes; From 31bcbbb5be04c7036223ce680a12927f5e51dc77 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:27 +0200 Subject: [PATCH 769/814] vfio/migration: Implement VFIO migration protocol v2 Implement the basic mandatory part of VFIO migration protocol v2. This includes all functionality that is necessary to support VFIO_MIGRATION_STOP_COPY part of the v2 protocol. The two protocols, v1 and v2, will co-exist and in the following patches v1 protocol code will be removed. There are several main differences between v1 and v2 protocols: - VFIO device state is now represented as a finite state machine instead of a bitmap. - Migration interface with kernel is now done using VFIO_DEVICE_FEATURE ioctl and normal read() and write() instead of the migration region. - Pre-copy is made optional in v2 protocol. Support for pre-copy will be added later on. Detailed information about VFIO migration protocol v2 and its difference compared to v1 protocol can be found here [1]. [1] https://lore.kernel.org/all/20220224142024.147653-10-yishaih@nvidia.com/ Signed-off-by: Avihai Horon Reviewed-by: Juan Quintela . Link: https://lore.kernel.org/r/20230216143630.25610-9-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 17 +- hw/vfio/migration.c | 483 +++++++++++++++++++++++++++++++--- hw/vfio/trace-events | 7 + include/hw/vfio/vfio-common.h | 5 + 4 files changed, 471 insertions(+), 41 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 1c974e9c5a..54fee2d5de 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -408,10 +408,17 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return false; } - if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) && + if (!migration->v2 && + (vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) && (migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING)) { return false; } + + if (migration->v2 && + vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF && + migration->device_state == VFIO_DEVICE_STATE_RUNNING) { + return false; + } } } return true; @@ -438,7 +445,13 @@ static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) return false; } - if (migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING) { + if (!migration->v2 && + migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING) { + continue; + } + + if (migration->v2 && + migration->device_state == VFIO_DEVICE_STATE_RUNNING) { continue; } else { return false; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index a5fe285721..452d96a520 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "qemu/cutils.h" +#include "qemu/units.h" #include #include @@ -44,8 +45,114 @@ #define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) #define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) +/* + * This is an arbitrary size based on migration of mlx5 devices, where typically + * total device migration size is on the order of 100s of MB. Testing with + * larger values, e.g. 128MB and 1GB, did not show a performance improvement. + */ +#define VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE (1 * MiB) + static int64_t bytes_transferred; +static const char *mig_state_to_str(enum vfio_device_mig_state state) +{ + switch (state) { + case VFIO_DEVICE_STATE_ERROR: + return "ERROR"; + case VFIO_DEVICE_STATE_STOP: + return "STOP"; + case VFIO_DEVICE_STATE_RUNNING: + return "RUNNING"; + case VFIO_DEVICE_STATE_STOP_COPY: + return "STOP_COPY"; + case VFIO_DEVICE_STATE_RESUMING: + return "RESUMING"; + default: + return "UNKNOWN STATE"; + } +} + +static int vfio_migration_set_state(VFIODevice *vbasedev, + enum vfio_device_mig_state new_state, + enum vfio_device_mig_state recover_state) +{ + VFIOMigration *migration = vbasedev->migration; + uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) + + sizeof(struct vfio_device_feature_mig_state), + sizeof(uint64_t))] = {}; + struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; + struct vfio_device_feature_mig_state *mig_state = + (struct vfio_device_feature_mig_state *)feature->data; + int ret; + + feature->argsz = sizeof(buf); + feature->flags = + VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_MIG_DEVICE_STATE; + mig_state->device_state = new_state; + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + /* Try to set the device in some good state */ + ret = -errno; + + if (recover_state == VFIO_DEVICE_STATE_ERROR) { + error_report("%s: Failed setting device state to %s, err: %s. " + "Recover state is ERROR. Resetting device", + vbasedev->name, mig_state_to_str(new_state), + strerror(errno)); + + goto reset_device; + } + + error_report( + "%s: Failed setting device state to %s, err: %s. Setting device in recover state %s", + vbasedev->name, mig_state_to_str(new_state), + strerror(errno), mig_state_to_str(recover_state)); + + mig_state->device_state = recover_state; + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + ret = -errno; + error_report( + "%s: Failed setting device in recover state, err: %s. Resetting device", + vbasedev->name, strerror(errno)); + + goto reset_device; + } + + migration->device_state = recover_state; + + return ret; + } + + migration->device_state = new_state; + if (mig_state->data_fd != -1) { + if (migration->data_fd != -1) { + /* + * This can happen if the device is asynchronously reset and + * terminates a data transfer. + */ + error_report("%s: data_fd out of sync", vbasedev->name); + close(mig_state->data_fd); + + return -EBADF; + } + + migration->data_fd = mig_state->data_fd; + } + + trace_vfio_migration_set_state(vbasedev->name, mig_state_to_str(new_state)); + + return 0; + +reset_device: + if (ioctl(vbasedev->fd, VFIO_DEVICE_RESET)) { + hw_error("%s: Failed resetting device, err: %s", vbasedev->name, + strerror(errno)); + } + + migration->device_state = VFIO_DEVICE_STATE_RUNNING; + + return ret; +} + static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, off_t off, bool iswrite) { @@ -260,6 +367,18 @@ static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) return ret; } +static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, + uint64_t data_size) +{ + VFIOMigration *migration = vbasedev->migration; + int ret; + + ret = qemu_file_get_to_fd(f, migration->data_fd, data_size); + trace_vfio_load_state_device_data(vbasedev->name, data_size, ret); + + return ret; +} + static int vfio_v1_load_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t data_size) { @@ -394,6 +513,14 @@ static int vfio_load_device_config_state(QEMUFile *f, void *opaque) return qemu_file_get_error(f); } +static void vfio_migration_cleanup(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + + close(migration->data_fd); + migration->data_fd = -1; +} + static void vfio_migration_v1_cleanup(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; @@ -403,8 +530,80 @@ static void vfio_migration_v1_cleanup(VFIODevice *vbasedev) } } +static int vfio_query_stop_copy_size(VFIODevice *vbasedev, + uint64_t *stop_copy_size) +{ + uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) + + sizeof(struct vfio_device_feature_mig_data_size), + sizeof(uint64_t))] = {}; + struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; + struct vfio_device_feature_mig_data_size *mig_data_size = + (struct vfio_device_feature_mig_data_size *)feature->data; + + feature->argsz = sizeof(buf); + feature->flags = + VFIO_DEVICE_FEATURE_GET | VFIO_DEVICE_FEATURE_MIG_DATA_SIZE; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + return -errno; + } + + *stop_copy_size = mig_data_size->stop_copy_length; + + return 0; +} + +/* Returns 1 if end-of-stream is reached, 0 if more data and -errno if error */ +static int vfio_save_block(QEMUFile *f, VFIOMigration *migration) +{ + ssize_t data_size; + + data_size = read(migration->data_fd, migration->data_buffer, + migration->data_buffer_size); + if (data_size < 0) { + return -errno; + } + if (data_size == 0) { + return 1; + } + + 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); + bytes_transferred += data_size; + + trace_vfio_save_block(migration->vbasedev->name, data_size); + + return qemu_file_get_error(f); +} + /* ---------------------------------------------------------------------- */ +static int vfio_save_setup(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + uint64_t stop_copy_size = VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE; + + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE); + + vfio_query_stop_copy_size(vbasedev, &stop_copy_size); + migration->data_buffer_size = MIN(VFIO_MIG_DEFAULT_DATA_BUFFER_SIZE, + stop_copy_size); + migration->data_buffer = g_try_malloc0(migration->data_buffer_size); + if (!migration->data_buffer) { + error_report("%s: Failed to allocate migration data buffer", + vbasedev->name); + return -ENOMEM; + } + + trace_vfio_save_setup(vbasedev->name, migration->data_buffer_size); + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + + return qemu_file_get_error(f); +} + static int vfio_v1_save_setup(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -448,6 +647,17 @@ static int vfio_v1_save_setup(QEMUFile *f, void *opaque) return 0; } +static void vfio_save_cleanup(void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + + g_free(migration->data_buffer); + migration->data_buffer = NULL; + vfio_migration_cleanup(vbasedev); + trace_vfio_save_cleanup(vbasedev->name); +} + static void vfio_v1_save_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; @@ -456,6 +666,35 @@ static void vfio_v1_save_cleanup(void *opaque) trace_vfio_save_cleanup(vbasedev->name); } +/* + * Migration size of VFIO devices can be as little as a few KBs or as big as + * many GBs. This value should be big enough to cover the worst case. + */ +#define VFIO_MIG_STOP_COPY_SIZE (100 * GiB) + +/* + * Only exact function is implemented and not estimate function. The reason is + * that during pre-copy phase of migration the estimate function is called + * repeatedly while pending RAM size is over the threshold, thus migration + * can't converge and querying the VFIO device pending data size is useless. + */ +static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy, + uint64_t *can_postcopy) +{ + VFIODevice *vbasedev = opaque; + uint64_t stop_copy_size = VFIO_MIG_STOP_COPY_SIZE; + + /* + * If getting pending migration size fails, VFIO_MIG_STOP_COPY_SIZE is + * reported so downtime limit won't be violated. + */ + vfio_query_stop_copy_size(vbasedev, &stop_copy_size); + *must_precopy += stop_copy_size; + + trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy, + stop_copy_size); +} + static void vfio_v1_state_pending(void *opaque, uint64_t *must_precopy, uint64_t *can_postcopy) { @@ -520,6 +759,42 @@ static int vfio_save_iterate(QEMUFile *f, void *opaque) return 0; } +static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + int ret; + + /* We reach here with device state STOP only */ + ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP_COPY, + VFIO_DEVICE_STATE_STOP); + if (ret) { + return ret; + } + + do { + ret = vfio_save_block(f, vbasedev->migration); + if (ret < 0) { + return ret; + } + } while (!ret); + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + ret = qemu_file_get_error(f); + if (ret) { + return ret; + } + + /* + * If setting the device in STOP state fails, the device should be reset. + * To do so, use ERROR state as a recover state. + */ + ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP, + VFIO_DEVICE_STATE_ERROR); + trace_vfio_save_complete_precopy(vbasedev->name, ret); + + return ret; +} + static int vfio_v1_save_complete_precopy(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -589,6 +864,14 @@ static void vfio_save_state(QEMUFile *f, void *opaque) } } +static int vfio_load_setup(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + + return vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RESUMING, + vbasedev->migration->device_state); +} + static int vfio_v1_load_setup(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -616,6 +899,16 @@ static int vfio_v1_load_setup(QEMUFile *f, void *opaque) return ret; } +static int vfio_load_cleanup(void *opaque) +{ + VFIODevice *vbasedev = opaque; + + vfio_migration_cleanup(vbasedev); + trace_vfio_load_cleanup(vbasedev->name); + + return 0; +} + static int vfio_v1_load_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; @@ -658,7 +951,11 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) uint64_t data_size = qemu_get_be64(f); if (data_size) { - ret = vfio_v1_load_buffer(f, vbasedev, data_size); + if (vbasedev->migration->v2) { + ret = vfio_load_buffer(f, vbasedev, data_size); + } else { + ret = vfio_v1_load_buffer(f, vbasedev, data_size); + } if (ret < 0) { return ret; } @@ -679,6 +976,17 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) return ret; } +static const SaveVMHandlers savevm_vfio_handlers = { + .save_setup = vfio_save_setup, + .save_cleanup = vfio_save_cleanup, + .state_pending_exact = vfio_state_pending_exact, + .save_live_complete_precopy = vfio_save_complete_precopy, + .save_state = vfio_save_state, + .load_setup = vfio_load_setup, + .load_cleanup = vfio_load_cleanup, + .load_state = vfio_load_state, +}; + static SaveVMHandlers savevm_vfio_v1_handlers = { .save_setup = vfio_v1_save_setup, .save_cleanup = vfio_v1_save_cleanup, @@ -694,6 +1002,38 @@ static SaveVMHandlers savevm_vfio_v1_handlers = { /* ---------------------------------------------------------------------- */ +static void vfio_vmstate_change(void *opaque, bool running, RunState state) +{ + VFIODevice *vbasedev = opaque; + enum vfio_device_mig_state new_state; + int ret; + + if (running) { + new_state = VFIO_DEVICE_STATE_RUNNING; + } else { + new_state = VFIO_DEVICE_STATE_STOP; + } + + /* + * If setting the device in new_state fails, the device should be reset. + * To do so, use ERROR state as a recover state. + */ + ret = vfio_migration_set_state(vbasedev, new_state, + VFIO_DEVICE_STATE_ERROR); + if (ret) { + /* + * Migration should be aborted in this case, but vm_state_notify() + * currently does not support reporting failures. + */ + if (migrate_get_current()->to_dst_file) { + qemu_file_set_error(migrate_get_current()->to_dst_file, ret); + } + } + + trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), + mig_state_to_str(new_state)); +} + static void vfio_v1_vmstate_change(void *opaque, bool running, RunState state) { VFIODevice *vbasedev = opaque; @@ -767,12 +1107,21 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) case MIGRATION_STATUS_CANCELLED: case MIGRATION_STATUS_FAILED: bytes_transferred = 0; - ret = vfio_migration_v1_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_V1_SAVING | - VFIO_DEVICE_STATE_V1_RESUMING), - VFIO_DEVICE_STATE_V1_RUNNING); - if (ret) { - error_report("%s: Failed to set state RUNNING", vbasedev->name); + if (migration->v2) { + /* + * If setting the device in RUNNING state fails, the device should + * be reset. To do so, use ERROR state as a recover state. + */ + vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RUNNING, + VFIO_DEVICE_STATE_ERROR); + } else { + ret = vfio_migration_v1_set_state(vbasedev, + ~(VFIO_DEVICE_STATE_V1_SAVING | + VFIO_DEVICE_STATE_V1_RESUMING), + VFIO_DEVICE_STATE_V1_RUNNING); + if (ret) { + error_report("%s: Failed to set state RUNNING", vbasedev->name); + } } } } @@ -781,12 +1130,42 @@ static void vfio_migration_exit(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; - vfio_region_exit(&migration->region); - vfio_region_finalize(&migration->region); + if (!migration->v2) { + vfio_region_exit(&migration->region); + vfio_region_finalize(&migration->region); + } g_free(vbasedev->migration); vbasedev->migration = NULL; } +static int vfio_migration_query_flags(VFIODevice *vbasedev, uint64_t *mig_flags) +{ + uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) + + sizeof(struct vfio_device_feature_migration), + sizeof(uint64_t))] = {}; + struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; + struct vfio_device_feature_migration *mig = + (struct vfio_device_feature_migration *)feature->data; + + feature->argsz = sizeof(buf); + feature->flags = VFIO_DEVICE_FEATURE_GET | VFIO_DEVICE_FEATURE_MIGRATION; + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + if (errno == ENOTTY) { + error_report("%s: VFIO migration is not supported in kernel", + vbasedev->name); + } else { + error_report("%s: Failed to query VFIO migration support, err: %s", + vbasedev->name, strerror(errno)); + } + + return -errno; + } + + *mig_flags = mig->flags; + + return 0; +} + static int vfio_migration_init(VFIODevice *vbasedev) { int ret; @@ -795,6 +1174,7 @@ static int vfio_migration_init(VFIODevice *vbasedev) char id[256] = ""; g_autofree char *path = NULL, *oid = NULL; struct vfio_region_info *info; + uint64_t mig_flags = 0; if (!vbasedev->ops->vfio_get_object) { return -EINVAL; @@ -805,35 +1185,51 @@ static int vfio_migration_init(VFIODevice *vbasedev) return -EINVAL; } - ret = vfio_get_dev_region_info(vbasedev, - VFIO_REGION_TYPE_MIGRATION_DEPRECATED, - VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, - &info); - if (ret) { + ret = vfio_migration_query_flags(vbasedev, &mig_flags); + if (!ret) { + /* Migration v2 */ + /* Basic migration functionality must be supported */ + if (!(mig_flags & VFIO_MIGRATION_STOP_COPY)) { + return -EOPNOTSUPP; + } + vbasedev->migration = g_new0(VFIOMigration, 1); + vbasedev->migration->device_state = VFIO_DEVICE_STATE_RUNNING; + vbasedev->migration->data_fd = -1; + vbasedev->migration->v2 = true; + } else if (ret == -ENOTTY) { + /* Migration v1 */ + ret = vfio_get_dev_region_info(vbasedev, + VFIO_REGION_TYPE_MIGRATION_DEPRECATED, + VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, + &info); + if (ret) { + return ret; + } + + vbasedev->migration = g_new0(VFIOMigration, 1); + vbasedev->migration->device_state_v1 = VFIO_DEVICE_STATE_V1_RUNNING; + vbasedev->migration->vm_running = runstate_is_running(); + + ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, + info->index, "migration"); + if (ret) { + error_report("%s: Failed to setup VFIO migration region %d: %s", + vbasedev->name, info->index, strerror(-ret)); + goto err; + } + + if (!vbasedev->migration->region.size) { + error_report("%s: Invalid zero-sized VFIO migration region %d", + vbasedev->name, info->index); + ret = -EINVAL; + goto err; + } + + g_free(info); + } else { return ret; } - vbasedev->migration = g_new0(VFIOMigration, 1); - vbasedev->migration->device_state_v1 = VFIO_DEVICE_STATE_V1_RUNNING; - vbasedev->migration->vm_running = runstate_is_running(); - - ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, - info->index, "migration"); - if (ret) { - error_report("%s: Failed to setup VFIO migration region %d: %s", - vbasedev->name, info->index, strerror(-ret)); - goto err; - } - - if (!vbasedev->migration->region.size) { - error_report("%s: Invalid zero-sized VFIO migration region %d", - vbasedev->name, info->index); - ret = -EINVAL; - goto err; - } - - g_free(info); - migration = vbasedev->migration; migration->vbasedev = vbasedev; @@ -845,11 +1241,20 @@ static int vfio_migration_init(VFIODevice *vbasedev) } strpadcpy(id, sizeof(id), path, '\0'); - register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, - &savevm_vfio_v1_handlers, vbasedev); + if (migration->v2) { + register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, + &savevm_vfio_handlers, vbasedev); + + migration->vm_state = qdev_add_vm_change_state_handler( + vbasedev->dev, vfio_vmstate_change, vbasedev); + } else { + register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, + &savevm_vfio_v1_handlers, vbasedev); + + migration->vm_state = qdev_add_vm_change_state_handler( + vbasedev->dev, vfio_v1_vmstate_change, vbasedev); + } - migration->vm_state = qdev_add_vm_change_state_handler( - vbasedev->dev, vfio_v1_vmstate_change, vbasedev); migration->migration_state.notify = vfio_migration_state_notifier; add_migration_state_change_notifier(&migration->migration_state); return 0; diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index c8739449df..b24e448534 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -149,20 +149,27 @@ vfio_display_edid_write_error(void) "" # migration.c vfio_migration_probe(const char *name) " (%s)" +vfio_migration_set_state(const char *name, const char *state) " (%s) state %s" vfio_migration_v1_set_state(const char *name, uint32_t state) " (%s) state %d" +vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s" vfio_v1_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" +vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64 vfio_v1_save_setup(const char *name) " (%s)" vfio_save_cleanup(const char *name) " (%s)" vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 vfio_save_device_config_state(const char *name) " (%s)" +vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64 vfio_v1_state_pending(const char *name, uint64_t precopy, uint64_t postcopy) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64 vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" +vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d" vfio_v1_save_complete_precopy(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 vfio_v1_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 +vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size 0x%"PRIx64" ret %d" vfio_load_cleanup(const char *name) " (%s)" vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 +vfio_save_block(const char *name, int data_size) " (%s) data_size %d" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 2c0fb1d622..c4eab55af9 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -66,6 +66,11 @@ typedef struct VFIOMigration { int vm_running; Notifier migration_state; uint64_t pending_bytes; + uint32_t device_state; + int data_fd; + void *data_buffer; + size_t data_buffer_size; + bool v2; } VFIOMigration; typedef struct VFIOAddressSpace { From 7429aebe1cff4bd2143fe5a690bf2892c5467932 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:28 +0200 Subject: [PATCH 770/814] vfio/migration: Remove VFIO migration protocol v1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that v2 protocol implementation has been added, remove the deprecated v1 implementation. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-10-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/common.c | 17 +- hw/vfio/migration.c | 700 ++-------------------------------- hw/vfio/trace-events | 9 - include/hw/vfio/vfio-common.h | 5 - 4 files changed, 24 insertions(+), 707 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 54fee2d5de..bab83c0e55 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -408,14 +408,7 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *container) return false; } - if (!migration->v2 && - (vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF) && - (migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING)) { - return false; - } - - if (migration->v2 && - vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF && + if (vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF && migration->device_state == VFIO_DEVICE_STATE_RUNNING) { return false; } @@ -445,13 +438,7 @@ static bool vfio_devices_all_running_and_mig_active(VFIOContainer *container) return false; } - if (!migration->v2 && - migration->device_state_v1 & VFIO_DEVICE_STATE_V1_RUNNING) { - continue; - } - - if (migration->v2 && - migration->device_state == VFIO_DEVICE_STATE_RUNNING) { + if (migration->device_state == VFIO_DEVICE_STATE_RUNNING) { continue; } else { return false; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 452d96a520..a2c3d9bade 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -153,220 +153,6 @@ reset_device: return ret; } -static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, - off_t off, bool iswrite) -{ - int ret; - - ret = iswrite ? pwrite(vbasedev->fd, val, count, off) : - pread(vbasedev->fd, val, count, off); - if (ret < count) { - error_report("vfio_mig_%s %d byte %s: failed at offset 0x%" - HWADDR_PRIx", err: %s", iswrite ? "write" : "read", count, - vbasedev->name, off, strerror(errno)); - return (ret < 0) ? ret : -EINVAL; - } - return 0; -} - -static int vfio_mig_rw(VFIODevice *vbasedev, __u8 *buf, size_t count, - off_t off, bool iswrite) -{ - int ret, done = 0; - __u8 *tbuf = buf; - - while (count) { - int bytes = 0; - - if (count >= 8 && !(off % 8)) { - bytes = 8; - } else if (count >= 4 && !(off % 4)) { - bytes = 4; - } else if (count >= 2 && !(off % 2)) { - bytes = 2; - } else { - bytes = 1; - } - - ret = vfio_mig_access(vbasedev, tbuf, bytes, off, iswrite); - if (ret) { - return ret; - } - - count -= bytes; - done += bytes; - off += bytes; - tbuf += bytes; - } - return done; -} - -#define vfio_mig_read(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, false) -#define vfio_mig_write(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, true) - -#define VFIO_MIG_STRUCT_OFFSET(f) \ - offsetof(struct vfio_device_migration_info, f) -/* - * Change the device_state register for device @vbasedev. Bits set in @mask - * are preserved, bits set in @value are set, and bits not set in either @mask - * or @value are cleared in device_state. If the register cannot be accessed, - * the resulting state would be invalid, or the device enters an error state, - * an error is returned. - */ - -static int vfio_migration_v1_set_state(VFIODevice *vbasedev, uint32_t mask, - uint32_t value) -{ - VFIOMigration *migration = vbasedev->migration; - VFIORegion *region = &migration->region; - off_t dev_state_off = region->fd_offset + - VFIO_MIG_STRUCT_OFFSET(device_state); - uint32_t device_state; - int ret; - - ret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), - dev_state_off); - if (ret < 0) { - return ret; - } - - device_state = (device_state & mask) | value; - - if (!VFIO_DEVICE_STATE_VALID(device_state)) { - return -EINVAL; - } - - ret = vfio_mig_write(vbasedev, &device_state, sizeof(device_state), - dev_state_off); - if (ret < 0) { - int rret; - - rret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), - dev_state_off); - - if ((rret < 0) || (VFIO_DEVICE_STATE_IS_ERROR(device_state))) { - hw_error("%s: Device in error state 0x%x", vbasedev->name, - device_state); - return rret ? rret : -EIO; - } - return ret; - } - - migration->device_state_v1 = device_state; - trace_vfio_migration_v1_set_state(vbasedev->name, device_state); - return 0; -} - -static void *get_data_section_size(VFIORegion *region, uint64_t data_offset, - uint64_t data_size, uint64_t *size) -{ - void *ptr = NULL; - uint64_t limit = 0; - int i; - - if (!region->mmaps) { - if (size) { - *size = MIN(data_size, region->size - data_offset); - } - return ptr; - } - - for (i = 0; i < region->nr_mmaps; i++) { - VFIOMmap *map = region->mmaps + i; - - if ((data_offset >= map->offset) && - (data_offset < map->offset + map->size)) { - - /* check if data_offset is within sparse mmap areas */ - ptr = map->mmap + data_offset - map->offset; - if (size) { - *size = MIN(data_size, map->offset + map->size - data_offset); - } - break; - } else if ((data_offset < map->offset) && - (!limit || limit > map->offset)) { - /* - * data_offset is not within sparse mmap areas, find size of - * non-mapped area. Check through all list since region->mmaps list - * is not sorted. - */ - limit = map->offset; - } - } - - if (!ptr && size) { - *size = limit ? MIN(data_size, limit - data_offset) : data_size; - } - return ptr; -} - -static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) -{ - VFIOMigration *migration = vbasedev->migration; - VFIORegion *region = &migration->region; - uint64_t data_offset = 0, data_size = 0, sz; - int ret; - - ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), - region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); - if (ret < 0) { - return ret; - } - - ret = vfio_mig_read(vbasedev, &data_size, sizeof(data_size), - region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); - if (ret < 0) { - return ret; - } - - trace_vfio_save_buffer(vbasedev->name, data_offset, data_size, - migration->pending_bytes); - - qemu_put_be64(f, data_size); - sz = data_size; - - while (sz) { - void *buf; - uint64_t sec_size; - bool buf_allocated = false; - - buf = get_data_section_size(region, data_offset, sz, &sec_size); - - if (!buf) { - buf = g_try_malloc(sec_size); - if (!buf) { - error_report("%s: Error allocating buffer ", __func__); - return -ENOMEM; - } - buf_allocated = true; - - ret = vfio_mig_read(vbasedev, buf, sec_size, - region->fd_offset + data_offset); - if (ret < 0) { - g_free(buf); - return ret; - } - } - - qemu_put_buffer(f, buf, sec_size); - - if (buf_allocated) { - g_free(buf); - } - sz -= sec_size; - data_offset += sec_size; - } - - ret = qemu_file_get_error(f); - - if (!ret && size) { - *size = data_size; - } - - bytes_transferred += data_size; - return ret; -} - static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t data_size) { @@ -379,96 +165,6 @@ static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, return ret; } -static int vfio_v1_load_buffer(QEMUFile *f, VFIODevice *vbasedev, - uint64_t data_size) -{ - VFIORegion *region = &vbasedev->migration->region; - uint64_t data_offset = 0, size, report_size; - int ret; - - do { - ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), - region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); - if (ret < 0) { - return ret; - } - - if (data_offset + data_size > region->size) { - /* - * If data_size is greater than the data section of migration region - * then iterate the write buffer operation. This case can occur if - * size of migration region at destination is smaller than size of - * migration region at source. - */ - report_size = size = region->size - data_offset; - data_size -= size; - } else { - report_size = size = data_size; - data_size = 0; - } - - trace_vfio_v1_load_state_device_data(vbasedev->name, data_offset, size); - - while (size) { - void *buf; - uint64_t sec_size; - bool buf_alloc = false; - - buf = get_data_section_size(region, data_offset, size, &sec_size); - - if (!buf) { - buf = g_try_malloc(sec_size); - if (!buf) { - error_report("%s: Error allocating buffer ", __func__); - return -ENOMEM; - } - buf_alloc = true; - } - - qemu_get_buffer(f, buf, sec_size); - - if (buf_alloc) { - ret = vfio_mig_write(vbasedev, buf, sec_size, - region->fd_offset + data_offset); - g_free(buf); - - if (ret < 0) { - return ret; - } - } - size -= sec_size; - data_offset += sec_size; - } - - ret = vfio_mig_write(vbasedev, &report_size, sizeof(report_size), - region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); - if (ret < 0) { - return ret; - } - } while (data_size); - - return 0; -} - -static int vfio_update_pending(VFIODevice *vbasedev) -{ - VFIOMigration *migration = vbasedev->migration; - VFIORegion *region = &migration->region; - uint64_t pending_bytes = 0; - int ret; - - ret = vfio_mig_read(vbasedev, &pending_bytes, sizeof(pending_bytes), - region->fd_offset + VFIO_MIG_STRUCT_OFFSET(pending_bytes)); - if (ret < 0) { - migration->pending_bytes = 0; - return ret; - } - - migration->pending_bytes = pending_bytes; - trace_vfio_update_pending(vbasedev->name, pending_bytes); - return 0; -} - static int vfio_save_device_config_state(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -521,15 +217,6 @@ static void vfio_migration_cleanup(VFIODevice *vbasedev) migration->data_fd = -1; } -static void vfio_migration_v1_cleanup(VFIODevice *vbasedev) -{ - VFIOMigration *migration = vbasedev->migration; - - if (migration->region.mmaps) { - vfio_region_unmap(&migration->region); - } -} - static int vfio_query_stop_copy_size(VFIODevice *vbasedev, uint64_t *stop_copy_size) { @@ -604,49 +291,6 @@ static int vfio_save_setup(QEMUFile *f, void *opaque) return qemu_file_get_error(f); } -static int vfio_v1_save_setup(QEMUFile *f, void *opaque) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - int ret; - - trace_vfio_v1_save_setup(vbasedev->name); - - qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE); - - if (migration->region.mmaps) { - /* - * Calling vfio_region_mmap() from migration thread. Memory API called - * from this function require locking the iothread when called from - * outside the main loop thread. - */ - qemu_mutex_lock_iothread(); - ret = vfio_region_mmap(&migration->region); - qemu_mutex_unlock_iothread(); - if (ret) { - error_report("%s: Failed to mmap VFIO migration region: %s", - vbasedev->name, strerror(-ret)); - error_report("%s: Falling back to slow path", vbasedev->name); - } - } - - ret = vfio_migration_v1_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_V1_SAVING); - if (ret) { - error_report("%s: Failed to set state SAVING", vbasedev->name); - return ret; - } - - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - - ret = qemu_file_get_error(f); - if (ret) { - return ret; - } - - return 0; -} - static void vfio_save_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; @@ -658,14 +302,6 @@ static void vfio_save_cleanup(void *opaque) trace_vfio_save_cleanup(vbasedev->name); } -static void vfio_v1_save_cleanup(void *opaque) -{ - VFIODevice *vbasedev = opaque; - - vfio_migration_v1_cleanup(vbasedev); - trace_vfio_save_cleanup(vbasedev->name); -} - /* * Migration size of VFIO devices can be as little as a few KBs or as big as * many GBs. This value should be big enough to cover the worst case. @@ -695,70 +331,6 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy, stop_copy_size); } -static void vfio_v1_state_pending(void *opaque, uint64_t *must_precopy, - uint64_t *can_postcopy) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - int ret; - - ret = vfio_update_pending(vbasedev); - if (ret) { - return; - } - - *must_precopy += migration->pending_bytes; - - trace_vfio_v1_state_pending(vbasedev->name, *must_precopy, *can_postcopy); -} - -static int vfio_save_iterate(QEMUFile *f, void *opaque) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - uint64_t data_size; - int ret; - - qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); - - if (migration->pending_bytes == 0) { - ret = vfio_update_pending(vbasedev); - if (ret) { - return ret; - } - - if (migration->pending_bytes == 0) { - qemu_put_be64(f, 0); - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - /* indicates data finished, goto complete phase */ - return 1; - } - } - - ret = vfio_save_buffer(f, vbasedev, &data_size); - if (ret) { - error_report("%s: vfio_save_buffer failed %s", vbasedev->name, - strerror(errno)); - return ret; - } - - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - - ret = qemu_file_get_error(f); - if (ret) { - return ret; - } - - /* - * Reset pending_bytes as state_pending* are not called during - * savevm or snapshot case, in such case vfio_update_pending() at - * the start of this function updates pending_bytes. - */ - migration->pending_bytes = 0; - trace_vfio_save_iterate(vbasedev->name, data_size); - return 0; -} - static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -795,62 +367,6 @@ static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) return ret; } -static int vfio_v1_save_complete_precopy(QEMUFile *f, void *opaque) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - uint64_t data_size; - int ret; - - ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_RUNNING, - VFIO_DEVICE_STATE_V1_SAVING); - if (ret) { - error_report("%s: Failed to set state STOP and SAVING", - vbasedev->name); - return ret; - } - - ret = vfio_update_pending(vbasedev); - if (ret) { - return ret; - } - - while (migration->pending_bytes > 0) { - qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); - ret = vfio_save_buffer(f, vbasedev, &data_size); - if (ret < 0) { - error_report("%s: Failed to save buffer", vbasedev->name); - return ret; - } - - if (data_size == 0) { - break; - } - - ret = vfio_update_pending(vbasedev); - if (ret) { - return ret; - } - } - - qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); - - ret = qemu_file_get_error(f); - if (ret) { - return ret; - } - - ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_V1_SAVING, - 0); - if (ret) { - error_report("%s: Failed to set state STOPPED", vbasedev->name); - return ret; - } - - trace_vfio_v1_save_complete_precopy(vbasedev->name); - return ret; -} - static void vfio_save_state(QEMUFile *f, void *opaque) { VFIODevice *vbasedev = opaque; @@ -872,33 +388,6 @@ static int vfio_load_setup(QEMUFile *f, void *opaque) vbasedev->migration->device_state); } -static int vfio_v1_load_setup(QEMUFile *f, void *opaque) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - int ret = 0; - - if (migration->region.mmaps) { - ret = vfio_region_mmap(&migration->region); - if (ret) { - error_report("%s: Failed to mmap VFIO migration region %d: %s", - vbasedev->name, migration->region.nr, - strerror(-ret)); - error_report("%s: Falling back to slow path", vbasedev->name); - } - } - - ret = vfio_migration_v1_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, - VFIO_DEVICE_STATE_V1_RESUMING); - if (ret) { - error_report("%s: Failed to set state RESUMING", vbasedev->name); - if (migration->region.mmaps) { - vfio_region_unmap(&migration->region); - } - } - return ret; -} - static int vfio_load_cleanup(void *opaque) { VFIODevice *vbasedev = opaque; @@ -909,15 +398,6 @@ static int vfio_load_cleanup(void *opaque) return 0; } -static int vfio_v1_load_cleanup(void *opaque) -{ - VFIODevice *vbasedev = opaque; - - vfio_migration_v1_cleanup(vbasedev); - trace_vfio_load_cleanup(vbasedev->name); - return 0; -} - static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) { VFIODevice *vbasedev = opaque; @@ -951,11 +431,7 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) uint64_t data_size = qemu_get_be64(f); if (data_size) { - if (vbasedev->migration->v2) { - ret = vfio_load_buffer(f, vbasedev, data_size); - } else { - ret = vfio_v1_load_buffer(f, vbasedev, data_size); - } + ret = vfio_load_buffer(f, vbasedev, data_size); if (ret < 0) { return ret; } @@ -987,19 +463,6 @@ static const SaveVMHandlers savevm_vfio_handlers = { .load_state = vfio_load_state, }; -static SaveVMHandlers savevm_vfio_v1_handlers = { - .save_setup = vfio_v1_save_setup, - .save_cleanup = vfio_v1_save_cleanup, - .state_pending_exact = vfio_v1_state_pending, - .state_pending_estimate = vfio_v1_state_pending, - .save_live_iterate = vfio_save_iterate, - .save_live_complete_precopy = vfio_v1_save_complete_precopy, - .save_state = vfio_save_state, - .load_setup = vfio_v1_load_setup, - .load_cleanup = vfio_v1_load_cleanup, - .load_state = vfio_load_state, -}; - /* ---------------------------------------------------------------------- */ static void vfio_vmstate_change(void *opaque, bool running, RunState state) @@ -1034,70 +497,12 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) mig_state_to_str(new_state)); } -static void vfio_v1_vmstate_change(void *opaque, bool running, RunState state) -{ - VFIODevice *vbasedev = opaque; - VFIOMigration *migration = vbasedev->migration; - uint32_t value, mask; - int ret; - - if (vbasedev->migration->vm_running == running) { - return; - } - - if (running) { - /* - * Here device state can have one of _SAVING, _RESUMING or _STOP bit. - * Transition from _SAVING to _RUNNING can happen if there is migration - * failure, in that case clear _SAVING bit. - * Transition from _RESUMING to _RUNNING occurs during resuming - * phase, in that case clear _RESUMING bit. - * In both the above cases, set _RUNNING bit. - */ - mask = ~VFIO_DEVICE_STATE_MASK; - value = VFIO_DEVICE_STATE_V1_RUNNING; - } else { - /* - * Here device state could be either _RUNNING or _SAVING|_RUNNING. Reset - * _RUNNING bit - */ - mask = ~VFIO_DEVICE_STATE_V1_RUNNING; - - /* - * When VM state transition to stop for savevm command, device should - * start saving data. - */ - if (state == RUN_STATE_SAVE_VM) { - value = VFIO_DEVICE_STATE_V1_SAVING; - } else { - value = 0; - } - } - - ret = vfio_migration_v1_set_state(vbasedev, mask, value); - if (ret) { - /* - * Migration should be aborted in this case, but vm_state_notify() - * currently does not support reporting failures. - */ - error_report("%s: Failed to set device state 0x%x", vbasedev->name, - (migration->device_state_v1 & mask) | value); - if (migrate_get_current()->to_dst_file) { - qemu_file_set_error(migrate_get_current()->to_dst_file, ret); - } - } - vbasedev->migration->vm_running = running; - trace_vfio_v1_vmstate_change(vbasedev->name, running, RunState_str(state), - (migration->device_state_v1 & mask) | value); -} - static void vfio_migration_state_notifier(Notifier *notifier, void *data) { MigrationState *s = data; VFIOMigration *migration = container_of(notifier, VFIOMigration, migration_state); VFIODevice *vbasedev = migration->vbasedev; - int ret; trace_vfio_migration_state_notifier(vbasedev->name, MigrationStatus_str(s->state)); @@ -1107,33 +512,17 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data) case MIGRATION_STATUS_CANCELLED: case MIGRATION_STATUS_FAILED: bytes_transferred = 0; - if (migration->v2) { - /* - * If setting the device in RUNNING state fails, the device should - * be reset. To do so, use ERROR state as a recover state. - */ - vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RUNNING, - VFIO_DEVICE_STATE_ERROR); - } else { - ret = vfio_migration_v1_set_state(vbasedev, - ~(VFIO_DEVICE_STATE_V1_SAVING | - VFIO_DEVICE_STATE_V1_RESUMING), - VFIO_DEVICE_STATE_V1_RUNNING); - if (ret) { - error_report("%s: Failed to set state RUNNING", vbasedev->name); - } - } + /* + * If setting the device in RUNNING state fails, the device should + * be reset. To do so, use ERROR state as a recover state. + */ + vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RUNNING, + VFIO_DEVICE_STATE_ERROR); } } static void vfio_migration_exit(VFIODevice *vbasedev) { - VFIOMigration *migration = vbasedev->migration; - - if (!migration->v2) { - vfio_region_exit(&migration->region); - vfio_region_finalize(&migration->region); - } g_free(vbasedev->migration); vbasedev->migration = NULL; } @@ -1173,7 +562,6 @@ static int vfio_migration_init(VFIODevice *vbasedev) VFIOMigration *migration; char id[256] = ""; g_autofree char *path = NULL, *oid = NULL; - struct vfio_region_info *info; uint64_t mig_flags = 0; if (!vbasedev->ops->vfio_get_object) { @@ -1186,52 +574,20 @@ static int vfio_migration_init(VFIODevice *vbasedev) } ret = vfio_migration_query_flags(vbasedev, &mig_flags); - if (!ret) { - /* Migration v2 */ - /* Basic migration functionality must be supported */ - if (!(mig_flags & VFIO_MIGRATION_STOP_COPY)) { - return -EOPNOTSUPP; - } - vbasedev->migration = g_new0(VFIOMigration, 1); - vbasedev->migration->device_state = VFIO_DEVICE_STATE_RUNNING; - vbasedev->migration->data_fd = -1; - vbasedev->migration->v2 = true; - } else if (ret == -ENOTTY) { - /* Migration v1 */ - ret = vfio_get_dev_region_info(vbasedev, - VFIO_REGION_TYPE_MIGRATION_DEPRECATED, - VFIO_REGION_SUBTYPE_MIGRATION_DEPRECATED, - &info); - if (ret) { - return ret; - } - - vbasedev->migration = g_new0(VFIOMigration, 1); - vbasedev->migration->device_state_v1 = VFIO_DEVICE_STATE_V1_RUNNING; - vbasedev->migration->vm_running = runstate_is_running(); - - ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, - info->index, "migration"); - if (ret) { - error_report("%s: Failed to setup VFIO migration region %d: %s", - vbasedev->name, info->index, strerror(-ret)); - goto err; - } - - if (!vbasedev->migration->region.size) { - error_report("%s: Invalid zero-sized VFIO migration region %d", - vbasedev->name, info->index); - ret = -EINVAL; - goto err; - } - - g_free(info); - } else { + if (ret) { return ret; } + /* Basic migration functionality must be supported */ + if (!(mig_flags & VFIO_MIGRATION_STOP_COPY)) { + return -EOPNOTSUPP; + } + + vbasedev->migration = g_new0(VFIOMigration, 1); migration = vbasedev->migration; migration->vbasedev = vbasedev; + migration->device_state = VFIO_DEVICE_STATE_RUNNING; + migration->data_fd = -1; oid = vmstate_if_get_id(VMSTATE_IF(DEVICE(obj))); if (oid) { @@ -1241,28 +597,16 @@ static int vfio_migration_init(VFIODevice *vbasedev) } strpadcpy(id, sizeof(id), path, '\0'); - if (migration->v2) { - register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, - &savevm_vfio_handlers, vbasedev); - - migration->vm_state = qdev_add_vm_change_state_handler( - vbasedev->dev, vfio_vmstate_change, vbasedev); - } else { - register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, - &savevm_vfio_v1_handlers, vbasedev); - - migration->vm_state = qdev_add_vm_change_state_handler( - vbasedev->dev, vfio_v1_vmstate_change, vbasedev); - } + register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, &savevm_vfio_handlers, + vbasedev); + migration->vm_state = qdev_add_vm_change_state_handler(vbasedev->dev, + vfio_vmstate_change, + vbasedev); migration->migration_state.notify = vfio_migration_state_notifier; add_migration_state_change_notifier(&migration->migration_state); - return 0; -err: - g_free(info); - vfio_migration_exit(vbasedev); - return ret; + return 0; } /* ---------------------------------------------------------------------- */ diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index b24e448534..9d65c2da2e 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -150,24 +150,15 @@ vfio_display_edid_write_error(void) "" # migration.c vfio_migration_probe(const char *name) " (%s)" vfio_migration_set_state(const char *name, const char *state) " (%s) state %s" -vfio_migration_v1_set_state(const char *name, uint32_t state) " (%s) state %d" vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s" -vfio_v1_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64 -vfio_v1_save_setup(const char *name) " (%s)" vfio_save_cleanup(const char *name) " (%s)" -vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 -vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 vfio_save_device_config_state(const char *name) " (%s)" vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64 -vfio_v1_state_pending(const char *name, uint64_t precopy, uint64_t postcopy) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64 -vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d" -vfio_v1_save_complete_precopy(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 -vfio_v1_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size 0x%"PRIx64" ret %d" vfio_load_cleanup(const char *name) " (%s)" vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index c4eab55af9..87524c64a4 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -61,16 +61,11 @@ typedef struct VFIORegion { typedef struct VFIOMigration { struct VFIODevice *vbasedev; VMChangeStateEntry *vm_state; - VFIORegion region; - uint32_t device_state_v1; - int vm_running; Notifier migration_state; - uint64_t pending_bytes; uint32_t device_state; int data_fd; void *data_buffer; size_t data_buffer_size; - bool v2; } VFIOMigration; typedef struct VFIOAddressSpace { From 48e4d8289f7bf90947ec5621e3ad05aa594a36ea Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:29 +0200 Subject: [PATCH 771/814] vfio: Alphabetize migration section of VFIO trace-events file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort the migration section of VFIO trace events file alphabetically and move two misplaced traces to common.c section. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-11-avihaih@nvidia.com Signed-off-by: Alex Williamson --- hw/vfio/trace-events | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 9d65c2da2e..669d9fe07c 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -119,6 +119,8 @@ vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Devic 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/%0x8" vfio_dma_unmap_overflow_workaround(void) "" +vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 +vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 # platform.c vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" @@ -148,19 +150,17 @@ vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u" vfio_display_edid_write_error(void) "" # migration.c -vfio_migration_probe(const char *name) " (%s)" -vfio_migration_set_state(const char *name, const char *state) " (%s) state %s" -vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s" -vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" -vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64 -vfio_save_cleanup(const char *name) " (%s)" -vfio_save_device_config_state(const char *name) " (%s)" -vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64 -vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d" +vfio_load_cleanup(const char *name) " (%s)" vfio_load_device_config_state(const char *name) " (%s)" vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size 0x%"PRIx64" ret %d" -vfio_load_cleanup(const char *name) " (%s)" -vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 -vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 +vfio_migration_probe(const char *name) " (%s)" +vfio_migration_set_state(const char *name, const char *state) " (%s) state %s" +vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" vfio_save_block(const char *name, int data_size) " (%s) data_size %d" +vfio_save_cleanup(const char *name) " (%s)" +vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d" +vfio_save_device_config_state(const char *name) " (%s)" +vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64 +vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64 +vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s" From 2b0ab9e9d604342a383170d3966290a8b2092073 Mon Sep 17 00:00:00 2001 From: Avihai Horon Date: Thu, 16 Feb 2023 16:36:30 +0200 Subject: [PATCH 772/814] docs/devel: Align VFIO migration docs to v2 protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that VFIO migration protocol v2 has been implemented and v1 protocol has been removed, update the documentation according to v2 protocol. Signed-off-by: Avihai Horon Reviewed-by: Cédric Le Goater Reviewed-by: Juan Quintela Link: https://lore.kernel.org/r/20230216143630.25610-12-avihaih@nvidia.com Signed-off-by: Alex Williamson --- docs/devel/vfio-migration.rst | 72 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/docs/devel/vfio-migration.rst b/docs/devel/vfio-migration.rst index 673057c90d..c214c73e28 100644 --- a/docs/devel/vfio-migration.rst +++ b/docs/devel/vfio-migration.rst @@ -7,46 +7,43 @@ the guest is running on source host and restoring this saved state on the destination host. This document details how saving and restoring of VFIO devices is done in QEMU. -Migration of VFIO devices consists of two phases: the optional pre-copy phase, -and the stop-and-copy phase. The pre-copy phase is iterative and allows to -accommodate VFIO devices that have a large amount of data that needs to be -transferred. The iterative pre-copy phase of migration allows for the guest to -continue whilst the VFIO device state is transferred to the destination, this -helps to reduce the total downtime of the VM. VFIO devices can choose to skip -the pre-copy phase of migration by returning pending_bytes as zero during the -pre-copy phase. +Migration of VFIO devices currently consists of a single stop-and-copy phase. +During the stop-and-copy phase the guest is stopped and the entire VFIO device +data is transferred to the destination. + +The pre-copy phase of migration is currently not supported for VFIO devices. +Support for VFIO pre-copy will be added later on. + +Note that currently VFIO migration is supported only for a single device. This +is due to VFIO migration's lack of P2P support. However, P2P support is planned +to be added later on. A detailed description of the UAPI for VFIO device migration can be found in -the comment for the ``vfio_device_migration_info`` structure in the header -file linux-headers/linux/vfio.h. +the comment for the ``vfio_device_mig_state`` structure in the header file +linux-headers/linux/vfio.h. VFIO implements the device hooks for the iterative approach as follows: -* A ``save_setup`` function that sets up the migration region and sets _SAVING - flag in the VFIO device state. +* A ``save_setup`` function that sets up migration on the source. -* A ``load_setup`` function that sets up the migration region on the - destination and sets _RESUMING flag in the VFIO device state. +* A ``load_setup`` function that sets the VFIO device on the destination in + _RESUMING state. * A ``state_pending_exact`` function that reads pending_bytes from the vendor driver, which indicates the amount of data that the vendor driver has yet to save for the VFIO device. -* A ``save_live_iterate`` function that reads the VFIO device's data from the - vendor driver through the migration region during iterative phase. - * A ``save_state`` function to save the device config space if it is present. -* A ``save_live_complete_precopy`` function that resets _RUNNING flag from the - VFIO device state and iteratively copies the remaining data for the VFIO - device until the vendor driver indicates that no data remains (pending bytes - is zero). +* A ``save_live_complete_precopy`` function that sets the VFIO device in + _STOP_COPY state and iteratively copies the data for the VFIO device until + the vendor driver indicates that no data remains. * A ``load_state`` function that loads the config section and the data - sections that are generated by the save functions above + sections that are generated by the save functions above. * ``cleanup`` functions for both save and load that perform any migration - related cleanup, including unmapping the migration region + related cleanup. The VFIO migration code uses a VM state change handler to change the VFIO @@ -71,13 +68,13 @@ tracking can identify dirtied pages, but any page pinned by the vendor driver can also be written by the device. There is currently no device or IOMMU support for dirty page tracking in hardware. -By default, dirty pages are tracked when the device is in pre-copy as well as -stop-and-copy phase. So, a page pinned by the vendor driver will be copied to -the destination in both phases. Copying dirty pages in pre-copy phase helps -QEMU to predict if it can achieve its downtime tolerances. If QEMU during -pre-copy phase keeps finding dirty pages continuously, then it understands -that even in stop-and-copy phase, it is likely to find dirty pages and can -predict the downtime accordingly. +By default, dirty pages are tracked during pre-copy as well as stop-and-copy +phase. So, a page pinned by the vendor driver will be copied to the destination +in both phases. Copying dirty pages in pre-copy phase helps QEMU to predict if +it can achieve its downtime tolerances. If QEMU during pre-copy phase keeps +finding dirty pages continuously, then it understands that even in stop-and-copy +phase, it is likely to find dirty pages and can predict the downtime +accordingly. QEMU also provides a per device opt-out option ``pre-copy-dirty-page-tracking`` which disables querying the dirty bitmap during pre-copy phase. If it is set to @@ -111,23 +108,22 @@ Live migration save path | migrate_init spawns migration_thread Migration thread then calls each device's .save_setup() - (RUNNING, _SETUP, _RUNNING|_SAVING) + (RUNNING, _SETUP, _RUNNING) | - (RUNNING, _ACTIVE, _RUNNING|_SAVING) + (RUNNING, _ACTIVE, _RUNNING) If device is active, get pending_bytes by .state_pending_exact() If total pending_bytes >= threshold_size, call .save_live_iterate() - Data of VFIO device for pre-copy phase is copied Iterate till total pending bytes converge and are less than threshold | On migration completion, vCPU stops and calls .save_live_complete_precopy for - each active device. The VFIO device is then transitioned into _SAVING state - (FINISH_MIGRATE, _DEVICE, _SAVING) + each active device. The VFIO device is then transitioned into _STOP_COPY state + (FINISH_MIGRATE, _DEVICE, _STOP_COPY) | For the VFIO device, iterate in .save_live_complete_precopy until pending data is 0 - (FINISH_MIGRATE, _DEVICE, _STOPPED) + (FINISH_MIGRATE, _DEVICE, _STOP) | - (FINISH_MIGRATE, _COMPLETED, _STOPPED) + (FINISH_MIGRATE, _COMPLETED, _STOP) Migraton thread schedules cleanup bottom half and exits Live migration resume path @@ -136,7 +132,7 @@ Live migration resume path :: Incoming migration calls .load_setup for each device - (RESTORE_VM, _ACTIVE, _STOPPED) + (RESTORE_VM, _ACTIVE, _STOP) | For each device, .load_state is called for that device section data (RESTORE_VM, _ACTIVE, _RESUMING) From 57edb7e44489ec4d85075acba47223127ecf1521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 19 Jan 2023 19:57:36 +0100 Subject: [PATCH 773/814] MAINTAINERS: Add myself as VFIO reviewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To show my interest in the VFIO susbsystem, let's start reviewing code. Signed-off-by: Cédric Le Goater Link: https://lore.kernel.org/r/20230119185736.616664-1-clg@kaod.org Signed-off-by: Alex Williamson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fd54c1f140..3093cfb66e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1995,6 +1995,7 @@ F: hw/usb/dev-serial.c VFIO M: Alex Williamson +R: Cédric Le Goater S: Supported F: hw/vfio/* F: include/hw/vfio/ From 66169c3c60af5014c1940de7491fdf090e5a090a Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:42 -0500 Subject: [PATCH 774/814] hw/sparse-mem: clear memory on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use sparse-mem for fuzzing. For long-running fuzzing processes, we eventually end up with many allocated sparse-mem pages. To avoid this, clear the allocated pages on system-reset. Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny Reviewed-by: Philippe Mathieu-Daudé --- hw/mem/sparse-mem.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/mem/sparse-mem.c b/hw/mem/sparse-mem.c index e6640eb8e7..72f038d47d 100644 --- a/hw/mem/sparse-mem.c +++ b/hw/mem/sparse-mem.c @@ -77,6 +77,13 @@ static void sparse_mem_write(void *opaque, hwaddr addr, uint64_t v, } +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 = { .read = sparse_mem_read, .write = sparse_mem_write, @@ -123,7 +130,8 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp) assert(s->baseaddr + s->length > s->baseaddr); - s->mapped = g_hash_table_new(NULL, NULL); + s->mapped = g_hash_table_new_full(NULL, NULL, NULL, + (GDestroyNotify)g_free); memory_region_init_io(&s->mmio, OBJECT(s), &sparse_mem_ops, s, "sparse-mem", s->length); sysbus_init_mmio(sbd, &s->mmio); @@ -131,12 +139,15 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp) static void sparse_mem_class_init(ObjectClass *klass, void *data) { + ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, sparse_mem_properties); dc->desc = "Sparse Memory Device"; dc->realize = sparse_mem_realize; + + rc->phases.enter = sparse_mem_enter_reset; } static const TypeInfo sparse_mem_types[] = { From 8d1e76b35b420a6ecf3f69730a7588279031d617 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:43 -0500 Subject: [PATCH 775/814] fuzz: add fuzz_reset API As we are converting most fuzzers to rely on reboots to reset state, introduce an API to make sure reboots are invoked in a consistent manner. Signed-off-by: Alexander Bulekov --- tests/qtest/fuzz/fuzz.c | 6 ++++++ tests/qtest/fuzz/fuzz.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index eb7520544b..3bedb81b32 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -51,6 +51,12 @@ void flush_events(QTestState *s) } } +void fuzz_reset(QTestState *s) +{ + qemu_system_reset(SHUTDOWN_CAUSE_GUEST_RESET); + main_loop_wait(true); +} + static QTestState *qtest_setup(void) { qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts); diff --git a/tests/qtest/fuzz/fuzz.h b/tests/qtest/fuzz/fuzz.h index 327c1c5a55..21d1362d65 100644 --- a/tests/qtest/fuzz/fuzz.h +++ b/tests/qtest/fuzz/fuzz.h @@ -103,7 +103,7 @@ typedef struct FuzzTarget { } FuzzTarget; void flush_events(QTestState *); -void reboot(QTestState *); +void fuzz_reset(QTestState *); /* Use the QTest ASCII protocol or call address_space API directly?*/ void fuzz_qtest_set_serialize(bool option); From 1375104370fc80bbcaa55430d2fbc0b1d8fc158b Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:44 -0500 Subject: [PATCH 776/814] fuzz/generic-fuzz: use reboots instead of forks to reset state Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- tests/qtest/fuzz/generic_fuzz.c | 116 +++++++------------------------- 1 file changed, 23 insertions(+), 93 deletions(-) diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index 7326f6840b..f4acfa45cc 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -18,7 +18,6 @@ #include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" -#include "fork_fuzz.h" #include "string.h" #include "exec/memory.h" #include "exec/ramblock.h" @@ -29,6 +28,8 @@ #include "generic_fuzz_configs.h" #include "hw/mem/sparse-mem.h" +static void pci_enum(gpointer pcidev, gpointer bus); + /* * SEPARATOR is used to separate "operations" in the fuzz input */ @@ -47,7 +48,6 @@ enum cmds { OP_CLOCK_STEP, }; -#define DEFAULT_TIMEOUT_US 100000 #define USEC_IN_SEC 1000000000 #define MAX_DMA_FILL_SIZE 0x10000 @@ -60,8 +60,6 @@ typedef struct { ram_addr_t size; /* The number of bytes until the end of the I/O region */ } address_range; -static useconds_t timeout = DEFAULT_TIMEOUT_US; - static bool qtest_log_enabled; MemoryRegion *sparse_mem_mr; @@ -589,30 +587,6 @@ static void op_disable_pci(QTestState *s, const unsigned char *data, size_t len) pci_disabled = true; } -static void handle_timeout(int sig) -{ - if (qtest_log_enabled) { - fprintf(stderr, "[Timeout]\n"); - fflush(stderr); - } - - /* - * If there is a crash, libfuzzer/ASAN forks a child to run an - * "llvm-symbolizer" process for printing out a pretty stacktrace. It - * communicates with this child using a pipe. If we timeout+Exit, while - * libfuzzer is still communicating with the llvm-symbolizer child, we will - * be left with an orphan llvm-symbolizer process. Sometimes, this appears - * to lead to a deadlock in the forkserver. Use waitpid to check if there - * are any waitable children. If so, exit out of the signal-handler, and - * let libfuzzer finish communicating with the child, and exit, on its own. - */ - if (waitpid(-1, NULL, WNOHANG) == 0) { - return; - } - - _Exit(0); -} - /* * Here, we interpret random bytes from the fuzzer, as a sequence of commands. * Some commands can be variable-width, so we use a separator, SEPARATOR, to @@ -669,64 +643,32 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size) size_t cmd_len; uint8_t op; - if (fork() == 0) { - struct sigaction sact; - struct itimerval timer; - sigset_t set; - /* - * Sometimes the fuzzer will find inputs that take quite a long time to - * process. Often times, these inputs do not result in new coverage. - * Even if these inputs might be interesting, they can slow down the - * fuzzer, overall. Set a timeout for each command to avoid hurting - * performance, too much - */ - if (timeout) { + op_clear_dma_patterns(s, NULL, 0); + pci_disabled = false; - sigemptyset(&sact.sa_mask); - sact.sa_flags = SA_NODEFER; - sact.sa_handler = handle_timeout; - sigaction(SIGALRM, &sact, NULL); + QPCIBus *pcibus = qpci_new_pc(s, NULL); + g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus); + qpci_free_pc(pcibus); - sigemptyset(&set); - sigaddset(&set, SIGALRM); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); + while (cmd && Size) { + /* Get the length until the next command or end of input */ + nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR)); + cmd_len = nextcmd ? nextcmd - cmd : Size; - memset(&timer, 0, sizeof(timer)); - timer.it_value.tv_sec = timeout / USEC_IN_SEC; - timer.it_value.tv_usec = timeout % USEC_IN_SEC; + if (cmd_len > 0) { + /* Interpret the first byte of the command as an opcode */ + op = *cmd % (sizeof(ops) / sizeof((ops)[0])); + ops[op](s, cmd + 1, cmd_len - 1); + + /* Run the main loop */ + flush_events(s); } - - op_clear_dma_patterns(s, NULL, 0); - pci_disabled = false; - - while (cmd && Size) { - /* Reset the timeout, each time we run a new command */ - if (timeout) { - setitimer(ITIMER_REAL, &timer, NULL); - } - - /* Get the length until the next command or end of input */ - nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR)); - cmd_len = nextcmd ? nextcmd - cmd : Size; - - if (cmd_len > 0) { - /* Interpret the first byte of the command as an opcode */ - op = *cmd % (sizeof(ops) / sizeof((ops)[0])); - ops[op](s, cmd + 1, cmd_len - 1); - - /* Run the main loop */ - flush_events(s); - } - /* Advance to the next command */ - cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd; - Size = Size - (cmd_len + sizeof(SEPARATOR) - 1); - g_array_set_size(dma_regions, 0); - } - _Exit(0); - } else { - flush_events(s); - wait(0); + /* Advance to the next command */ + cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd; + Size = Size - (cmd_len + sizeof(SEPARATOR) - 1); + g_array_set_size(dma_regions, 0); } + fuzz_reset(s); } static void usage(void) @@ -738,8 +680,6 @@ static void usage(void) printf("Optionally: QEMU_AVOID_DOUBLE_FETCH= " "Try to avoid racy DMA double fetch bugs? %d by default\n", avoid_double_fetches); - printf("Optionally: QEMU_FUZZ_TIMEOUT= Specify a custom timeout (us). " - "0 to disable. %d by default\n", timeout); exit(0); } @@ -825,7 +765,6 @@ static void generic_pre_fuzz(QTestState *s) { GHashTableIter iter; MemoryRegion *mr; - QPCIBus *pcibus; char **result; GString *name_pattern; @@ -838,9 +777,6 @@ static void generic_pre_fuzz(QTestState *s) if (getenv("QEMU_AVOID_DOUBLE_FETCH")) { avoid_double_fetches = 1; } - if (getenv("QEMU_FUZZ_TIMEOUT")) { - timeout = g_ascii_strtoll(getenv("QEMU_FUZZ_TIMEOUT"), NULL, 0); - } qts_global = s; /* @@ -883,12 +819,6 @@ static void generic_pre_fuzz(QTestState *s) printf("No fuzzable memory regions found...\n"); exit(1); } - - pcibus = qpci_new_pc(s, NULL); - g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus); - qpci_free_pc(pcibus); - - counter_shm_init(); } /* From b8b52178e2d84bfcda91b00d55fa05ed895badbf Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:45 -0500 Subject: [PATCH 777/814] fuzz/generic-fuzz: add a limit on DMA bytes written MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we have repplaced fork-based fuzzing, with reboots - we can no longer use a timeout+exit() to avoid slow inputs. Libfuzzer has its own timer that it uses to catch slow inputs, however these timeouts are usually seconds-minutes long: more than enough to bog-down the fuzzing process. However, I found that slow inputs often attempt to fill overly large DMA requests. Thus, we can mitigate most timeouts by setting a cap on the total number of DMA bytes written by an input. Signed-off-by: Alexander Bulekov Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Darren Kenny --- tests/qtest/fuzz/generic_fuzz.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index f4acfa45cc..c525d22951 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -51,6 +51,7 @@ enum cmds { #define USEC_IN_SEC 1000000000 #define MAX_DMA_FILL_SIZE 0x10000 +#define MAX_TOTAL_DMA_SIZE 0x10000000 #define PCI_HOST_BRIDGE_CFG 0xcf8 #define PCI_HOST_BRIDGE_DATA 0xcfc @@ -61,6 +62,7 @@ typedef struct { } address_range; static bool qtest_log_enabled; +size_t dma_bytes_written; MemoryRegion *sparse_mem_mr; @@ -194,6 +196,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr) */ if (dma_patterns->len == 0 || len == 0 + || dma_bytes_written + len > MAX_TOTAL_DMA_SIZE || (mr != current_machine->ram && mr != sparse_mem_mr)) { return; } @@ -266,6 +269,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr) fflush(stderr); } qtest_memwrite(qts_global, addr, buf, l); + dma_bytes_written += l; } len -= l; buf += l; @@ -645,6 +649,7 @@ static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size) op_clear_dma_patterns(s, NULL, 0); pci_disabled = false; + dma_bytes_written = 0; QPCIBus *pcibus = qpci_new_pc(s, NULL); g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus); From 5d3c73e27e7e0ab09e4796a6218cb5762632c4e2 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:46 -0500 Subject: [PATCH 778/814] fuzz/virtio-scsi: remove fork-based fuzzer Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- tests/qtest/fuzz/virtio_scsi_fuzz.c | 51 ++++------------------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/tests/qtest/fuzz/virtio_scsi_fuzz.c b/tests/qtest/fuzz/virtio_scsi_fuzz.c index b3220ef6cb..b6268efd59 100644 --- a/tests/qtest/fuzz/virtio_scsi_fuzz.c +++ b/tests/qtest/fuzz/virtio_scsi_fuzz.c @@ -20,7 +20,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "standard-headers/linux/virtio_scsi.h" #include "fuzz.h" -#include "fork_fuzz.h" #include "qos_fuzz.h" #define PCI_SLOT 0x02 @@ -132,48 +131,24 @@ static void virtio_scsi_fuzz(QTestState *s, QVirtioSCSIQueues* queues, } } -static void virtio_scsi_fork_fuzz(QTestState *s, - const unsigned char *Data, size_t Size) -{ - QVirtioSCSI *scsi = fuzz_qos_obj; - static QVirtioSCSIQueues *queues; - if (!queues) { - queues = qvirtio_scsi_init(scsi->vdev, 0); - } - if (fork() == 0) { - virtio_scsi_fuzz(s, queues, Data, Size); - flush_events(s); - _Exit(0); - } else { - flush_events(s); - wait(NULL); - } -} - static void virtio_scsi_with_flag_fuzz(QTestState *s, const unsigned char *Data, size_t Size) { QVirtioSCSI *scsi = fuzz_qos_obj; static QVirtioSCSIQueues *queues; - if (fork() == 0) { - if (Size >= sizeof(uint64_t)) { - queues = qvirtio_scsi_init(scsi->vdev, *(uint64_t *)Data); - virtio_scsi_fuzz(s, queues, - Data + sizeof(uint64_t), Size - sizeof(uint64_t)); - flush_events(s); - } - _Exit(0); - } else { + if (Size >= sizeof(uint64_t)) { + queues = qvirtio_scsi_init(scsi->vdev, *(uint64_t *)Data); + virtio_scsi_fuzz(s, queues, + Data + sizeof(uint64_t), Size - sizeof(uint64_t)); flush_events(s); - wait(NULL); } + fuzz_reset(s); } static void virtio_scsi_pre_fuzz(QTestState *s) { qos_init_path(s); - counter_shm_init(); } static void *virtio_scsi_test_setup(GString *cmd_line, void *arg) @@ -189,22 +164,10 @@ static void *virtio_scsi_test_setup(GString *cmd_line, void *arg) static void register_virtio_scsi_fuzz_targets(void) { - fuzz_add_qos_target(&(FuzzTarget){ - .name = "virtio-scsi-fuzz", - .description = "Fuzz the virtio-scsi virtual queues, forking " - "for each fuzz run", - .pre_vm_init = &counter_shm_init, - .pre_fuzz = &virtio_scsi_pre_fuzz, - .fuzz = virtio_scsi_fork_fuzz,}, - "virtio-scsi", - &(QOSGraphTestOptions){.before = virtio_scsi_test_setup} - ); - fuzz_add_qos_target(&(FuzzTarget){ .name = "virtio-scsi-flags-fuzz", - .description = "Fuzz the virtio-scsi virtual queues, forking " - "for each fuzz run (also fuzzes the virtio flags)", - .pre_vm_init = &counter_shm_init, + .description = "Fuzz the virtio-scsi virtual queues. " + "Also fuzzes the virtio flags", .pre_fuzz = &virtio_scsi_pre_fuzz, .fuzz = virtio_scsi_with_flag_fuzz,}, "virtio-scsi", From 5f47d07fd80cc2b500eb2df5b15130feb50d6338 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:47 -0500 Subject: [PATCH 779/814] fuzz/virtio-net: remove fork-based fuzzer Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- tests/qtest/fuzz/virtio_net_fuzz.c | 54 +++--------------------------- 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c index c2c15f07f0..e239875e3b 100644 --- a/tests/qtest/fuzz/virtio_net_fuzz.c +++ b/tests/qtest/fuzz/virtio_net_fuzz.c @@ -16,7 +16,6 @@ #include "tests/qtest/libqtest.h" #include "tests/qtest/libqos/virtio-net.h" #include "fuzz.h" -#include "fork_fuzz.h" #include "qos_fuzz.h" @@ -115,36 +114,18 @@ static void virtio_net_fuzz_multi(QTestState *s, } } -static void virtio_net_fork_fuzz(QTestState *s, - const unsigned char *Data, size_t Size) -{ - if (fork() == 0) { - virtio_net_fuzz_multi(s, Data, Size, false); - flush_events(s); - _Exit(0); - } else { - flush_events(s); - wait(NULL); - } -} -static void virtio_net_fork_fuzz_check_used(QTestState *s, +static void virtio_net_fuzz_check_used(QTestState *s, const unsigned char *Data, size_t Size) { - if (fork() == 0) { - virtio_net_fuzz_multi(s, Data, Size, true); - flush_events(s); - _Exit(0); - } else { - flush_events(s); - wait(NULL); - } + virtio_net_fuzz_multi(s, Data, Size, true); + flush_events(s); + fuzz_reset(s); } static void virtio_net_pre_fuzz(QTestState *s) { qos_init_path(s); - counter_shm_init(); } static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg) @@ -158,23 +139,8 @@ static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg) return arg; } -static void *virtio_net_test_setup_user(GString *cmd_line, void *arg) -{ - g_string_append_printf(cmd_line, " -netdev user,id=hs0 "); - return arg; -} - static void register_virtio_net_fuzz_targets(void) { - fuzz_add_qos_target(&(FuzzTarget){ - .name = "virtio-net-socket", - .description = "Fuzz the virtio-net virtual queues. Fuzz incoming " - "traffic using the socket backend", - .pre_fuzz = &virtio_net_pre_fuzz, - .fuzz = virtio_net_fork_fuzz,}, - "virtio-net", - &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} - ); fuzz_add_qos_target(&(FuzzTarget){ .name = "virtio-net-socket-check-used", @@ -182,20 +148,10 @@ static void register_virtio_net_fuzz_targets(void) "descriptors to be used. Timeout may indicate improperly handled " "input", .pre_fuzz = &virtio_net_pre_fuzz, - .fuzz = virtio_net_fork_fuzz_check_used,}, + .fuzz = virtio_net_fuzz_check_used,}, "virtio-net", &(QOSGraphTestOptions){.before = virtio_net_test_setup_socket} ); - fuzz_add_qos_target(&(FuzzTarget){ - .name = "virtio-net-slirp", - .description = "Fuzz the virtio-net virtual queues with the slirp " - " backend. Warning: May result in network traffic emitted from the " - " process. Run in an isolated network environment.", - .pre_fuzz = &virtio_net_pre_fuzz, - .fuzz = virtio_net_fork_fuzz,}, - "virtio-net", - &(QOSGraphTestOptions){.before = virtio_net_test_setup_user} - ); } fuzz_target_init(register_virtio_net_fuzz_targets); From 725767e9a1fd4c39628f9ad10cb7aa0fe98a04cc Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:48 -0500 Subject: [PATCH 780/814] fuzz/virtio-blk: remove fork-based fuzzer Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- tests/qtest/fuzz/virtio_blk_fuzz.c | 51 ++++-------------------------- 1 file changed, 7 insertions(+), 44 deletions(-) diff --git a/tests/qtest/fuzz/virtio_blk_fuzz.c b/tests/qtest/fuzz/virtio_blk_fuzz.c index a9fb9ecf6c..651fd4f043 100644 --- a/tests/qtest/fuzz/virtio_blk_fuzz.c +++ b/tests/qtest/fuzz/virtio_blk_fuzz.c @@ -19,7 +19,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "standard-headers/linux/virtio_blk.h" #include "fuzz.h" -#include "fork_fuzz.h" #include "qos_fuzz.h" #define TEST_IMAGE_SIZE (64 * 1024 * 1024) @@ -128,48 +127,24 @@ static void virtio_blk_fuzz(QTestState *s, QVirtioBlkQueues* queues, } } -static void virtio_blk_fork_fuzz(QTestState *s, - const unsigned char *Data, size_t Size) -{ - QVirtioBlk *blk = fuzz_qos_obj; - static QVirtioBlkQueues *queues; - if (!queues) { - queues = qvirtio_blk_init(blk->vdev, 0); - } - if (fork() == 0) { - virtio_blk_fuzz(s, queues, Data, Size); - flush_events(s); - _Exit(0); - } else { - flush_events(s); - wait(NULL); - } -} - static void virtio_blk_with_flag_fuzz(QTestState *s, const unsigned char *Data, size_t Size) { QVirtioBlk *blk = fuzz_qos_obj; static QVirtioBlkQueues *queues; - if (fork() == 0) { - if (Size >= sizeof(uint64_t)) { - queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data); - virtio_blk_fuzz(s, queues, - Data + sizeof(uint64_t), Size - sizeof(uint64_t)); - flush_events(s); - } - _Exit(0); - } else { + if (Size >= sizeof(uint64_t)) { + queues = qvirtio_blk_init(blk->vdev, *(uint64_t *)Data); + virtio_blk_fuzz(s, queues, + Data + sizeof(uint64_t), Size - sizeof(uint64_t)); flush_events(s); - wait(NULL); } + fuzz_reset(s); } static void virtio_blk_pre_fuzz(QTestState *s) { qos_init_path(s); - counter_shm_init(); } static void drive_destroy(void *path) @@ -208,22 +183,10 @@ static void *virtio_blk_test_setup(GString *cmd_line, void *arg) static void register_virtio_blk_fuzz_targets(void) { - fuzz_add_qos_target(&(FuzzTarget){ - .name = "virtio-blk-fuzz", - .description = "Fuzz the virtio-blk virtual queues, forking " - "for each fuzz run", - .pre_vm_init = &counter_shm_init, - .pre_fuzz = &virtio_blk_pre_fuzz, - .fuzz = virtio_blk_fork_fuzz,}, - "virtio-blk", - &(QOSGraphTestOptions){.before = virtio_blk_test_setup} - ); - fuzz_add_qos_target(&(FuzzTarget){ .name = "virtio-blk-flags-fuzz", - .description = "Fuzz the virtio-blk virtual queues, forking " - "for each fuzz run (also fuzzes the virtio flags)", - .pre_vm_init = &counter_shm_init, + .description = "Fuzz the virtio-blk virtual queues. " + "Also fuzzes the virtio flags)", .pre_fuzz = &virtio_blk_pre_fuzz, .fuzz = virtio_blk_with_flag_fuzz,}, "virtio-blk", From f031c95941e3dbc816416d5336ed6225a4933cfc Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:49 -0500 Subject: [PATCH 781/814] fuzz/i440fx: remove fork-based fuzzer Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- tests/qtest/fuzz/i440fx_fuzz.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/tests/qtest/fuzz/i440fx_fuzz.c b/tests/qtest/fuzz/i440fx_fuzz.c index b17fc725df..155fe018f8 100644 --- a/tests/qtest/fuzz/i440fx_fuzz.c +++ b/tests/qtest/fuzz/i440fx_fuzz.c @@ -18,7 +18,6 @@ #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" #include "qos_fuzz.h" -#include "fork_fuzz.h" #define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8 @@ -89,6 +88,7 @@ static void i440fx_fuzz_qtest(QTestState *s, size_t Size) { ioport_fuzz_qtest(s, Data, Size); + fuzz_reset(s); } static void pciconfig_fuzz_qos(QTestState *s, QPCIBus *bus, @@ -145,17 +145,6 @@ static void i440fx_fuzz_qos(QTestState *s, pciconfig_fuzz_qos(s, bus, Data, Size); } -static void i440fx_fuzz_qos_fork(QTestState *s, - const unsigned char *Data, size_t Size) { - if (fork() == 0) { - i440fx_fuzz_qos(s, Data, Size); - _Exit(0); - } else { - flush_events(s); - wait(NULL); - } -} - static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest" " -m 0 -display none"; static GString *i440fx_argv(FuzzTarget *t) @@ -163,10 +152,6 @@ static GString *i440fx_argv(FuzzTarget *t) return g_string_new(i440fx_qtest_argv); } -static void fork_init(void) -{ - counter_shm_init(); -} static void register_pci_fuzz_targets(void) { @@ -178,16 +163,6 @@ static void register_pci_fuzz_targets(void) .get_init_cmdline = i440fx_argv, .fuzz = i440fx_fuzz_qtest}); - /* Uses libqos and forks to prevent state leakage */ - fuzz_add_qos_target(&(FuzzTarget){ - .name = "i440fx-qos-fork-fuzz", - .description = "Fuzz the i440fx using raw qtest commands and " - "rebooting after each run", - .pre_vm_init = &fork_init, - .fuzz = i440fx_fuzz_qos_fork,}, - "i440FX-pcihost", - &(QOSGraphTestOptions){} - ); /* * Uses libqos. Doesn't do anything to reset state. Note that if we were to From d2e6f9272d337d1b23b588e7ead8500d40cbf4e9 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:50 -0500 Subject: [PATCH 782/814] fuzz: remove fork-fuzzing scaffolding Fork-fuzzing provides a few pros, but our implementation prevents us from using fuzzers other than libFuzzer, and may be causing issues such as coverage-failure builds on OSS-Fuzz. It is not a great long-term solution as it depends on internal implementation details of libFuzzer (which is no longer in active development). Remove it in favor of other methods of resetting state between inputs. Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- meson.build | 4 --- tests/qtest/fuzz/fork_fuzz.c | 41 ------------------------- tests/qtest/fuzz/fork_fuzz.h | 23 -------------- tests/qtest/fuzz/fork_fuzz.ld | 56 ----------------------------------- tests/qtest/fuzz/meson.build | 6 ++-- 5 files changed, 3 insertions(+), 127 deletions(-) delete mode 100644 tests/qtest/fuzz/fork_fuzz.c delete mode 100644 tests/qtest/fuzz/fork_fuzz.h delete mode 100644 tests/qtest/fuzz/fork_fuzz.ld diff --git a/meson.build b/meson.build index a76c855312..b6f92bba35 100644 --- a/meson.build +++ b/meson.build @@ -215,10 +215,6 @@ endif # Specify linker-script with add_project_link_arguments so that it is not placed # within a linker --start-group/--end-group pair if get_option('fuzzing') - add_project_link_arguments(['-Wl,-T,', - (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')], - native: false, language: all_languages) - # Specify a filter to only instrument code that is directly related to # virtual-devices. configure_file(output: 'instrumentation-filter', diff --git a/tests/qtest/fuzz/fork_fuzz.c b/tests/qtest/fuzz/fork_fuzz.c deleted file mode 100644 index 6ffb2a7937..0000000000 --- a/tests/qtest/fuzz/fork_fuzz.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Fork-based fuzzing helpers - * - * Copyright Red Hat Inc., 2019 - * - * Authors: - * Alexander Bulekov - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "fork_fuzz.h" - - -void counter_shm_init(void) -{ - /* Copy what's in the counter region to a temporary buffer.. */ - void *copy = malloc(&__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); - memcpy(copy, - &__FUZZ_COUNTERS_START, - &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); - - /* Map a shared region over the counter region */ - if (mmap(&__FUZZ_COUNTERS_START, - &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START, - PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, - 0, 0) == MAP_FAILED) { - perror("Error: "); - exit(1); - } - - /* Copy the original data back to the counter-region */ - memcpy(&__FUZZ_COUNTERS_START, copy, - &__FUZZ_COUNTERS_END - &__FUZZ_COUNTERS_START); - free(copy); -} - - diff --git a/tests/qtest/fuzz/fork_fuzz.h b/tests/qtest/fuzz/fork_fuzz.h deleted file mode 100644 index 9ecb8b58ef..0000000000 --- a/tests/qtest/fuzz/fork_fuzz.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Fork-based fuzzing helpers - * - * Copyright Red Hat Inc., 2019 - * - * Authors: - * Alexander Bulekov - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef FORK_FUZZ_H -#define FORK_FUZZ_H - -extern uint8_t __FUZZ_COUNTERS_START; -extern uint8_t __FUZZ_COUNTERS_END; - -void counter_shm_init(void); - -#endif - diff --git a/tests/qtest/fuzz/fork_fuzz.ld b/tests/qtest/fuzz/fork_fuzz.ld deleted file mode 100644 index cfb88b7fdb..0000000000 --- a/tests/qtest/fuzz/fork_fuzz.ld +++ /dev/null @@ -1,56 +0,0 @@ -/* - * We adjust linker script modification to place all of the stuff that needs to - * persist across fuzzing runs into a contiguous section of memory. Then, it is - * easy to re-map the counter-related memory as shared. - */ - -SECTIONS -{ - .data.fuzz_start : ALIGN(4K) - { - __FUZZ_COUNTERS_START = .; - __start___sancov_cntrs = .; - *(_*sancov_cntrs); - __stop___sancov_cntrs = .; - - /* Lowest stack counter */ - *(__sancov_lowest_stack); - } -} -INSERT AFTER .data; - -SECTIONS -{ - .data.fuzz_ordered : - { - /* - * Coverage counters. They're not necessary for fuzzing, but are useful - * for analyzing the fuzzing performance - */ - __start___llvm_prf_cnts = .; - *(*llvm_prf_cnts); - __stop___llvm_prf_cnts = .; - - /* Internal Libfuzzer TracePC object which contains the ValueProfileMap */ - FuzzerTracePC*(.bss*); - /* - * In case the above line fails, explicitly specify the (mangled) name of - * the object we care about - */ - *(.bss._ZN6fuzzer3TPCE); - } -} -INSERT AFTER .data.fuzz_start; - -SECTIONS -{ - .data.fuzz_end : ALIGN(4K) - { - __FUZZ_COUNTERS_END = .; - } -} -/* - * Don't overwrite the SECTIONS in the default linker script. Instead insert the - * above into the default script - */ -INSERT AFTER .data.fuzz_ordered; diff --git a/tests/qtest/fuzz/meson.build b/tests/qtest/fuzz/meson.build index 189901d4a2..4d10b47b8f 100644 --- a/tests/qtest/fuzz/meson.build +++ b/tests/qtest/fuzz/meson.build @@ -2,7 +2,7 @@ if not get_option('fuzzing') subdir_done() endif -specific_fuzz_ss.add(files('fuzz.c', 'fork_fuzz.c', 'qos_fuzz.c', +specific_fuzz_ss.add(files('fuzz.c', 'qos_fuzz.c', 'qtest_wrappers.c'), qos) # Targets @@ -12,7 +12,7 @@ specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio_scsi_fuz specific_fuzz_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio_blk_fuzz.c')) specific_fuzz_ss.add(files('generic_fuzz.c')) -fork_fuzz = declare_dependency( +fuzz_ld = declare_dependency( link_args: fuzz_exe_ldflags + ['-Wl,-wrap,qtest_inb', '-Wl,-wrap,qtest_inw', @@ -35,4 +35,4 @@ fork_fuzz = declare_dependency( '-Wl,-wrap,qtest_memset'] ) -specific_fuzz_ss.add(fork_fuzz) +specific_fuzz_ss.add(fuzz_ld) From 7d9e5f18a94792ed875a1caed2bfcd1e68a49481 Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Sat, 4 Feb 2023 23:29:51 -0500 Subject: [PATCH 783/814] docs/fuzz: remove mentions of fork-based fuzzing Signed-off-by: Alexander Bulekov Reviewed-by: Darren Kenny --- docs/devel/fuzzing.rst | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/docs/devel/fuzzing.rst b/docs/devel/fuzzing.rst index 715330c856..3bfcb33fc4 100644 --- a/docs/devel/fuzzing.rst +++ b/docs/devel/fuzzing.rst @@ -19,11 +19,6 @@ responsibility to ensure that state is reset between fuzzing-runs. Building the fuzzers -------------------- -*NOTE*: If possible, build a 32-bit binary. When forking, the 32-bit fuzzer is -much faster, since the page-map has a smaller size. This is due to the fact that -AddressSanitizer maps ~20TB of memory, as part of its detection. This results -in a large page-map, and a much slower ``fork()``. - To build the fuzzers, install a recent version of clang: Configure with (substitute the clang binaries with the version you installed). Here, enable-sanitizers, is optional but it allows us to reliably detect bugs @@ -296,10 +291,9 @@ input. It is also responsible for manually calling ``main_loop_wait`` to ensure that bottom halves are executed and any cleanup required before the next input. Since the same process is reused for many fuzzing runs, QEMU state needs to -be reset at the end of each run. There are currently two implemented -options for resetting state: +be reset at the end of each run. For example, this can be done by rebooting the +VM, after each run. -- Reboot the guest between runs. - *Pros*: Straightforward and fast for simple fuzz targets. - *Cons*: Depending on the device, does not reset all device state. If the @@ -308,15 +302,3 @@ options for resetting state: reboot. - *Example target*: ``i440fx-qtest-reboot-fuzz`` - -- Run each test case in a separate forked process and copy the coverage - information back to the parent. This is fairly similar to AFL's "deferred" - fork-server mode [3] - - - *Pros*: Relatively fast. Devices only need to be initialized once. No need to - do slow reboots or vmloads. - - - *Cons*: Not officially supported by libfuzzer. Does not work well for - devices that rely on dedicated threads. - - - *Example target*: ``virtio-net-fork-fuzz`` From c6941b3b9b7445f7760c462882f8397b9dc51e30 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 10 Nov 2022 13:52:22 +0100 Subject: [PATCH 784/814] net: Move the code to collect available NIC models to a separate function The code that collects the available NIC models is not really specific to PCI anymore and will be required in the next patch, too, so let's move this into a new separate function in net.c instead. Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- hw/pci/pci.c | 29 +---------------------------- include/net/net.h | 14 ++++++++++++++ net/net.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 208c16f450..cc51f98593 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1789,7 +1789,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, const char *default_devaddr) { const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; - GSList *list; GPtrArray *pci_nic_models; PCIBus *bus; PCIDevice *pci_dev; @@ -1804,33 +1803,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, nd->model = g_strdup("virtio-net-pci"); } - list = object_class_get_list_sorted(TYPE_PCI_DEVICE, false); - pci_nic_models = g_ptr_array_new(); - while (list) { - DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data, - TYPE_DEVICE); - GSList *next; - if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) && - dc->user_creatable) { - const char *name = object_class_get_name(list->data); - /* - * A network device might also be something else than a NIC, see - * e.g. the "rocker" device. Thus we have to look for the "netdev" - * property, too. Unfortunately, some devices like virtio-net only - * create this property during instance_init, so we have to create - * a temporary instance here to be able to check it. - */ - Object *obj = object_new_with_class(OBJECT_CLASS(dc)); - if (object_property_find(obj, "netdev")) { - g_ptr_array_add(pci_nic_models, (gpointer)name); - } - object_unref(obj); - } - next = list->next; - g_slist_free_1(list); - list = next; - } - g_ptr_array_add(pci_nic_models, NULL); + pci_nic_models = qemu_get_nic_models(TYPE_PCI_DEVICE); if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) { exit(0); diff --git a/include/net/net.h b/include/net/net.h index fad589cc1d..1d88621c12 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -203,6 +203,20 @@ void net_socket_rs_init(SocketReadState *rs, bool vnet_hdr); NetClientState *qemu_get_peer(NetClientState *nc, int queue_index); +/** + * qemu_get_nic_models: + * @device_type: Defines which devices should be taken into consideration + * (e.g. TYPE_DEVICE for all devices, or TYPE_PCI_DEVICE for PCI) + * + * Get an array of pointers to names of NIC devices that are available in + * the QEMU binary. The array is terminated with a NULL pointer entry. + * The caller is responsible for freeing the memory when it is not required + * anymore, e.g. with g_ptr_array_free(..., true). + * + * Returns: Pointer to the array that contains the pointers to the names. + */ +GPtrArray *qemu_get_nic_models(const char *device_type); + /* NIC info */ #define MAX_NICS 8 diff --git a/net/net.c b/net/net.c index 251fc5ab55..476a4b71cc 100644 --- a/net/net.c +++ b/net/net.c @@ -899,6 +899,40 @@ static int nic_get_free_idx(void) return -1; } +GPtrArray *qemu_get_nic_models(const char *device_type) +{ + GPtrArray *nic_models = g_ptr_array_new(); + GSList *list = object_class_get_list_sorted(device_type, false); + + while (list) { + DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data, + TYPE_DEVICE); + GSList *next; + if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) && + dc->user_creatable) { + const char *name = object_class_get_name(list->data); + /* + * A network device might also be something else than a NIC, see + * e.g. the "rocker" device. Thus we have to look for the "netdev" + * property, too. Unfortunately, some devices like virtio-net only + * create this property during instance_init, so we have to create + * a temporary instance here to be able to check it. + */ + Object *obj = object_new_with_class(OBJECT_CLASS(dc)); + if (object_property_find(obj, "netdev")) { + g_ptr_array_add(nic_models, (gpointer)name); + } + object_unref(obj); + } + next = list->next; + g_slist_free_1(list); + list = next; + } + g_ptr_array_add(nic_models, NULL); + + return nic_models; +} + int qemu_show_nic_models(const char *arg, const char *const *models) { int i; From 27c819244b8129a4742bfe43d255cdaa8528765d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 10 Nov 2022 13:52:23 +0100 Subject: [PATCH 785/814] net: Restore printing of the help text with "-nic help" Running QEMU with "-nic help" used to work in QEMU 5.2 and earlier versions (it showed the available netdev backends), but this feature got broken during some refactoring in version 6.0. Let's restore the old behavior, and while we're at it, let's also print the available NIC models here now since this option can be used to configure both, netdev backend and model in one go. Fixes: ad6f932fe8 ("net: do not exit on "netdev_add help" monitor command") Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- net/net.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/net.c b/net/net.c index 476a4b71cc..e8cd95cb7e 100644 --- a/net/net.c +++ b/net/net.c @@ -1542,8 +1542,18 @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) const char *type; type = qemu_opt_get(opts, "type"); - if (type && g_str_equal(type, "none")) { - return 0; /* Nothing to do, default_net is cleared in vl.c */ + if (type) { + if (g_str_equal(type, "none")) { + return 0; /* Nothing to do, default_net is cleared in vl.c */ + } + if (is_help_option(type)) { + GPtrArray *nic_models = qemu_get_nic_models(TYPE_DEVICE); + show_netdevs(); + printf("\n"); + qemu_show_nic_models(type, (const char **)nic_models->pdata); + g_ptr_array_free(nic_models, true); + exit(0); + } } idx = nic_get_free_idx(); From 3b0cca8e4e674bda3457435208c3268767b6b085 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 10 Nov 2022 13:52:24 +0100 Subject: [PATCH 786/814] net: Replace "Supported NIC models" with "Available NIC models" Just because a NIC model is compiled into the QEMU binary does not necessary mean that it can be used with each and every machine. So let's rather talk about "available" models instead of "supported" models, just to avoid confusion. Reviewed-by: Claudio Fontana Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/net.c b/net/net.c index e8cd95cb7e..ebc7ce0231 100644 --- a/net/net.c +++ b/net/net.c @@ -941,7 +941,7 @@ int qemu_show_nic_models(const char *arg, const char *const *models) return 0; } - printf("Supported NIC models:\n"); + printf("Available NIC models:\n"); for (i = 0 ; models[i]; i++) { printf("%s\n", models[i]); } From 44c94cdb21cd1d1fb9aa6554585b94aa6de7ed9d Mon Sep 17 00:00:00 2001 From: Qiang Liu Date: Mon, 16 Jan 2023 11:14:31 +0800 Subject: [PATCH 787/814] hw/net/lan9118: log [read|write]b when mode_16bit is enabled rather than abort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces hw_error to guest error log for [read|write]b accesses when mode_16bit is enabled. This avoids aborting qemu. Fixes: 1248f8d4cbc3 ("hw/lan9118: Add basic 16-bit mode support.") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1433 Reported-by: Qiang Liu Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Qiang Liu Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/lan9118.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index f1cba55967..e5c4af182d 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -15,7 +15,6 @@ #include "migration/vmstate.h" #include "net/net.h" #include "net/eth.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/net/lan9118.h" #include "hw/ptimer.h" @@ -32,12 +31,8 @@ #ifdef DEBUG_LAN9118 #define DPRINTF(fmt, ...) \ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0) -#define BADF(fmt, ...) \ -do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0) #else #define DPRINTF(fmt, ...) do {} while(0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0) #endif /* The tx and rx fifo ports are a range of aliased 32-bit registers */ @@ -848,7 +843,8 @@ static uint32_t do_phy_read(lan9118_state *s, int reg) case 30: /* Interrupt mask */ return s->phy_int_mask; default: - BADF("PHY read reg %d\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, + "do_phy_read: PHY read reg %d\n", reg); return 0; } } @@ -876,7 +872,8 @@ static void do_phy_write(lan9118_state *s, int reg, uint32_t val) phy_update_irq(s); break; default: - BADF("PHY write reg %d = 0x%04x\n", reg, val); + qemu_log_mask(LOG_GUEST_ERROR, + "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val); } } @@ -1209,7 +1206,8 @@ static void lan9118_16bit_mode_write(void *opaque, hwaddr offset, return; } - hw_error("lan9118_write: Bad size 0x%x\n", size); + qemu_log_mask(LOG_GUEST_ERROR, + "lan9118_16bit_mode_write: Bad size 0x%x\n", size); } static uint64_t lan9118_readl(void *opaque, hwaddr offset, @@ -1324,7 +1322,8 @@ static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset, return lan9118_readl(opaque, offset, size); } - hw_error("lan9118_read: Bad size 0x%x\n", size); + qemu_log_mask(LOG_GUEST_ERROR, + "lan9118_16bit_mode_read: Bad size 0x%x\n", size); return 0; } From 099a63828130843741d317cb28e936f468b2b53b Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 25 Aug 2022 11:29:10 +0200 Subject: [PATCH 788/814] hw/net/vmxnet3: allow VMXNET3_MAX_MTU itself as a value Currently, VMXNET3_MAX_MTU itself (being 9000) is not considered a valid value for the MTU, but a guest running ESXi 7.0 might try to set it and fail the assert [0]. In the Linux kernel, dev->max_mtu itself is a valid value for the MTU and for the vmxnet3 driver it's 9000, so a guest running Linux will also fail the assert when trying to set an MTU of 9000. VMXNET3_MAX_MTU and s->mtu don't seem to be used in relation to buffer allocations/accesses, so allowing the upper limit itself as a value should be fine. [0]: https://forum.proxmox.com/threads/114011/ Fixes: d05dcd94ae ("net: vmxnet3: validate configuration values during activate (CVE-2021-20203)") Signed-off-by: Fiona Ebner Signed-off-by: Jason Wang --- hw/net/vmxnet3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index d2ab527ef4..56559cda24 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1441,7 +1441,7 @@ static void vmxnet3_activate_device(VMXNET3State *s) vmxnet3_setup_rx_filtering(s); /* Cache fields from shared memory */ s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); - assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU); + assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu <= VMXNET3_MAX_MTU); VMW_CFPRN("MTU is %u", s->mtu); s->max_rx_frags = From 0c65ef4fbbf3d3c1c4435f06db7648ab67935a19 Mon Sep 17 00:00:00 2001 From: Christian Svensson Date: Fri, 30 Dec 2022 21:27:10 +0100 Subject: [PATCH 789/814] net: Increase L2TPv3 buffer to fit jumboframes Increase the allocated buffer size to fit larger packets. Given that jumboframes can commonly be up to 9000 bytes the closest suitable value seems to be 16 KiB. Tested by running qemu towards a Linux L2TPv3 endpoint and pushing jumboframe traffic through the interfaces. Signed-off-by: Christian Svensson Signed-off-by: Jason Wang --- net/l2tpv3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tpv3.c b/net/l2tpv3.c index 53b2d32573..b5547cb917 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -42,7 +42,7 @@ */ #define BUFFER_ALIGN sysconf(_SC_PAGESIZE) -#define BUFFER_SIZE 2048 +#define BUFFER_SIZE 16384 #define IOVSIZE 2 #define MAX_L2TPV3_MSGCNT 64 #define MAX_L2TPV3_IOVCNT (MAX_L2TPV3_MSGCNT * IOVSIZE) From 993f71ee3360450c2758964adbdfb13f4d460162 Mon Sep 17 00:00:00 2001 From: Joelle van Dyne Date: Sun, 1 Jan 2023 17:08:21 -0800 Subject: [PATCH 790/814] vmnet: stop recieving events when VM is stopped When the VM is stopped using the HMP command "stop", soon the handler will stop reading from the vmnet interface. This causes a flood of `VMNET_INTERFACE_PACKETS_AVAILABLE` events to arrive and puts the host CPU at 100%. We fix this by removing the event handler from vmnet when the VM is no longer in a running state and restore it when we return to a running state. Signed-off-by: Joelle van Dyne Signed-off-by: Jason Wang --- net/vmnet-common.m | 48 +++++++++++++++++++++++++++++++++------------- net/vmnet_int.h | 2 ++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/net/vmnet-common.m b/net/vmnet-common.m index 2cb60b9ddd..2958283485 100644 --- a/net/vmnet-common.m +++ b/net/vmnet-common.m @@ -17,6 +17,7 @@ #include "clients.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "sysemu/runstate.h" #include #include @@ -242,6 +243,35 @@ static void vmnet_bufs_init(VmnetState *s) } } +/** + * Called on state change to un-register/re-register handlers + */ +static void vmnet_vm_state_change_cb(void *opaque, bool running, RunState state) +{ + VmnetState *s = opaque; + + if (running) { + vmnet_interface_set_event_callback( + s->vmnet_if, + VMNET_INTERFACE_PACKETS_AVAILABLE, + s->if_queue, + ^(interface_event_t event_id, xpc_object_t event) { + assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE); + /* + * This function is being called from a non qemu thread, so + * we only schedule a BH, and do the rest of the io completion + * handling from vmnet_send_bh() which runs in a qemu context. + */ + qemu_bh_schedule(s->send_bh); + }); + } else { + vmnet_interface_set_event_callback( + s->vmnet_if, + VMNET_INTERFACE_PACKETS_AVAILABLE, + NULL, + NULL); + } +} int vmnet_if_create(NetClientState *nc, xpc_object_t if_desc, @@ -329,19 +359,9 @@ int vmnet_if_create(NetClientState *nc, s->packets_send_current_pos = 0; s->packets_send_end_pos = 0; - vmnet_interface_set_event_callback( - s->vmnet_if, - VMNET_INTERFACE_PACKETS_AVAILABLE, - s->if_queue, - ^(interface_event_t event_id, xpc_object_t event) { - assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE); - /* - * This function is being called from a non qemu thread, so - * we only schedule a BH, and do the rest of the io completion - * handling from vmnet_send_bh() which runs in a qemu context. - */ - qemu_bh_schedule(s->send_bh); - }); + vmnet_vm_state_change_cb(s, 1, RUN_STATE_RUNNING); + + s->change = qemu_add_vm_change_state_handler(vmnet_vm_state_change_cb, s); return 0; } @@ -356,6 +376,8 @@ void vmnet_cleanup_common(NetClientState *nc) return; } + vmnet_vm_state_change_cb(s, 0, RUN_STATE_SHUTDOWN); + qemu_del_vm_change_state_handler(s->change); if_stopped_sem = dispatch_semaphore_create(0); vmnet_stop_interface( s->vmnet_if, diff --git a/net/vmnet_int.h b/net/vmnet_int.h index d0b90594f2..a8a033dc96 100644 --- a/net/vmnet_int.h +++ b/net/vmnet_int.h @@ -45,6 +45,8 @@ typedef struct VmnetState { int packets_send_end_pos; struct iovec iov_buf[VMNET_PACKETS_LIMIT]; + + VMChangeStateEntry *change; } VmnetState; const char *vmnet_status_map_str(vmnet_return_t status); From 148fbf0d58a6fa9c6881db28fced8c071c3be100 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 19 Jan 2023 11:16:45 +0100 Subject: [PATCH 791/814] net: stream: add a new option to automatically reconnect In stream mode, if the server shuts down there is currently no way to reconnect the client to a new server without removing the NIC device and the netdev backend (or to reboot). This patch introduces a reconnect option that specifies a delay to try to reconnect with the same parameters. Add a new test in qtest to test the reconnect option and the connect/disconnect events. Signed-off-by: Laurent Vivier Signed-off-by: Jason Wang --- net/stream.c | 53 ++++++++++++++++++- qapi/net.json | 7 ++- qemu-options.hx | 6 +-- tests/qtest/netdev-socket.c | 101 ++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 5 deletions(-) diff --git a/net/stream.c b/net/stream.c index 37ff727e0c..9204b4c96e 100644 --- a/net/stream.c +++ b/net/stream.c @@ -39,6 +39,8 @@ #include "io/channel-socket.h" #include "io/net-listener.h" #include "qapi/qapi-events-net.h" +#include "qapi/qapi-visit-sockets.h" +#include "qapi/clone-visitor.h" typedef struct NetStreamState { NetClientState nc; @@ -49,11 +51,15 @@ typedef struct NetStreamState { guint ioc_write_tag; SocketReadState rs; unsigned int send_index; /* number of bytes sent*/ + uint32_t reconnect; + guint timer_tag; + SocketAddress *addr; } NetStreamState; static void net_stream_listen(QIONetListener *listener, QIOChannelSocket *cioc, void *opaque); +static void net_stream_arm_reconnect(NetStreamState *s); static gboolean net_stream_writable(QIOChannel *ioc, GIOCondition condition, @@ -170,6 +176,7 @@ static gboolean net_stream_send(QIOChannel *ioc, qemu_set_info_str(&s->nc, "%s", ""); qapi_event_send_netdev_stream_disconnected(s->nc.name); + net_stream_arm_reconnect(s); return G_SOURCE_REMOVE; } @@ -187,6 +194,14 @@ static gboolean net_stream_send(QIOChannel *ioc, static void net_stream_cleanup(NetClientState *nc) { NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + if (s->timer_tag) { + g_source_remove(s->timer_tag); + s->timer_tag = 0; + } + if (s->addr) { + qapi_free_SocketAddress(s->addr); + s->addr = NULL; + } if (s->ioc) { if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) { if (s->ioc_read_tag) { @@ -346,12 +361,37 @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque) error: object_unref(OBJECT(s->ioc)); s->ioc = NULL; + net_stream_arm_reconnect(s); +} + +static gboolean net_stream_reconnect(gpointer data) +{ + NetStreamState *s = data; + QIOChannelSocket *sioc; + + s->timer_tag = 0; + + sioc = qio_channel_socket_new(); + s->ioc = QIO_CHANNEL(sioc); + qio_channel_socket_connect_async(sioc, s->addr, + net_stream_client_connected, s, + NULL, NULL); + return G_SOURCE_REMOVE; +} + +static void net_stream_arm_reconnect(NetStreamState *s) +{ + if (s->reconnect && s->timer_tag == 0) { + s->timer_tag = g_timeout_add_seconds(s->reconnect, + net_stream_reconnect, s); + } } static int net_stream_client_init(NetClientState *peer, const char *model, const char *name, SocketAddress *addr, + uint32_t reconnect, Error **errp) { NetStreamState *s; @@ -364,6 +404,10 @@ static int net_stream_client_init(NetClientState *peer, s->ioc = QIO_CHANNEL(sioc); s->nc.link_down = true; + s->reconnect = reconnect; + if (reconnect) { + s->addr = QAPI_CLONE(SocketAddress, addr); + } qio_channel_socket_connect_async(sioc, addr, net_stream_client_connected, s, NULL, NULL); @@ -380,7 +424,14 @@ int net_init_stream(const Netdev *netdev, const char *name, sock = &netdev->u.stream; if (!sock->has_server || !sock->server) { - return net_stream_client_init(peer, "stream", name, sock->addr, errp); + return net_stream_client_init(peer, "stream", name, sock->addr, + sock->has_reconnect ? sock->reconnect : 0, + errp); + } + if (sock->has_reconnect) { + error_setg(errp, "'reconnect' option is incompatible with " + "socket in server mode"); + return -1; } return net_stream_server_init(peer, "stream", name, sock->addr, errp); } diff --git a/qapi/net.json b/qapi/net.json index 522ac582ed..d6eb30008b 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -585,6 +585,10 @@ # @addr: socket address to listen on (server=true) # or connect to (server=false) # @server: create server socket (default: false) +# @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. (default: 0) +# (since 8.0) # # Only SocketAddress types 'unix', 'inet' and 'fd' are supported. # @@ -593,7 +597,8 @@ { 'struct': 'NetdevStreamOptions', 'data': { 'addr': 'SocketAddress', - '*server': 'bool' } } + '*server': 'bool', + '*reconnect': 'uint32' } } ## # @NetdevDgramOptions: diff --git a/qemu-options.hx b/qemu-options.hx index cafd8be8ed..beeb4475ba 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2762,9 +2762,9 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n" " configure a network backend to connect to another network\n" " using an UDP tunnel\n" - "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off]\n" - "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n" - "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n" + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]\n" + "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]\n" + "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]\n" " configure a network backend to connect to another network\n" " using a socket connection in stream mode.\n" "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n" diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c index 1d98dca821..270e424bee 100644 --- a/tests/qtest/netdev-socket.c +++ b/tests/qtest/netdev-socket.c @@ -11,6 +11,10 @@ #include #include "../unit/socket-helpers.h" #include "libqtest.h" +#include "qapi/qmp/qstring.h" +#include "qemu/sockets.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qapi-visit-sockets.h" #define CONNECTION_TIMEOUT 60 @@ -142,6 +146,101 @@ static void test_stream_inet_ipv4(void) qtest_quit(qts0); } +static void wait_stream_connected(QTestState *qts, const char *id, + SocketAddress **addr) +{ + QDict *resp, *data; + QString *qstr; + QObject *obj; + Visitor *v = NULL; + + resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED"); + g_assert_nonnull(resp); + data = qdict_get_qdict(resp, "data"); + g_assert_nonnull(data); + + qstr = qobject_to(QString, qdict_get(data, "netdev-id")); + g_assert_nonnull(data); + + g_assert(!strcmp(qstring_get_str(qstr), id)); + + obj = qdict_get(data, "addr"); + + v = qobject_input_visitor_new(obj); + visit_type_SocketAddress(v, NULL, addr, NULL); + visit_free(v); + qobject_unref(resp); +} + +static void wait_stream_disconnected(QTestState *qts, const char *id) +{ + QDict *resp, *data; + QString *qstr; + + resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED"); + g_assert_nonnull(resp); + data = qdict_get_qdict(resp, "data"); + g_assert_nonnull(data); + + qstr = qobject_to(QString, qdict_get(data, "netdev-id")); + g_assert_nonnull(data); + + g_assert(!strcmp(qstring_get_str(qstr), id)); + qobject_unref(resp); +} + +static void test_stream_inet_reconnect(void) +{ + QTestState *qts0, *qts1; + int port; + SocketAddress *addr; + + port = inet_get_free_port(false); + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off,reconnect=1," + "addr.host=127.0.0.1,addr.port=%d", port); + + wait_stream_connected(qts0, "st0", &addr); + g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); + g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); + qapi_free_SocketAddress(addr); + + /* kill server */ + qtest_quit(qts0); + + /* check client has been disconnected */ + wait_stream_disconnected(qts1, "st0"); + + /* restart server */ + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + /* wait connection events*/ + wait_stream_connected(qts0, "st0", &addr); + g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); + g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); + qapi_free_SocketAddress(addr); + + wait_stream_connected(qts1, "st0", &addr); + g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET); + g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1"); + g_assert_cmpint(atoi(addr->u.inet.port), ==, port); + qapi_free_SocketAddress(addr); + + qtest_quit(qts1); + qtest_quit(qts0); +} + static void test_stream_inet_ipv6(void) { QTestState *qts0, *qts1; @@ -418,6 +517,8 @@ int main(int argc, char **argv) #ifndef _WIN32 qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); #endif + qtest_add_func("/netdev/stream/inet/reconnect", + test_stream_inet_reconnect); } if (has_ipv6) { qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); From 525ae115222f0b0b6de7f9665976f640d18c200a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Tue, 17 Jan 2023 11:53:08 +0100 Subject: [PATCH 792/814] vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VHOST_BACKEND_F_IOTLB_ASID is the feature bit, not the bitmask. Since the device under test also provided VHOST_BACKEND_F_IOTLB_MSG_V2 and VHOST_BACKEND_F_IOTLB_BATCH, this went unnoticed. Fixes: c1a1008685 ("vdpa: always start CVQ in SVQ mode if possible") Signed-off-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: Jason Wang --- net/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 1a13a34d35..de5ed8ff22 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -384,7 +384,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) g_strerror(errno), errno); return -1; } - if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || + if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) || !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { return 0; } From deb9c2ad0b81ac25fa02935f28cabb9c6155f377 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Tue, 17 Jan 2023 08:52:01 -0500 Subject: [PATCH 793/814] util/qemu-thread-posix: use TSA_NO_TSA to suppress clang TSA warnings in FreeBSD FreeBSD implements pthread headers using TSA (thread safety analysis) annotations, therefore when an application is compiled with -Wthread-safety there are some locking/annotation requirements that the user of the pthread API has to follow. This will also be the case in QEMU, since util/qemu-thread-posix.c uses the pthread API. Therefore when building it with -Wthread-safety, the compiler will throw warnings because the functions are not properly annotated. We need TSA to be enabled because it ensures that the critical sections of an annotated variable are properly locked. In order to make the compiler happy and avoid adding all the necessary macros to all callers (lock functions should use TSA_ACQUIRE, while unlock TSA_RELEASE, and this applies to all users of pthread_mutex_lock and pthread_mutex_unlock), simply use TSA_NO_TSA to supppress such warnings. Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20230117135203.3049709-2-eesposit@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/qemu/thread.h | 14 +++++++++----- util/qemu-thread-posix.c | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 7841084199..dd3822d7ce 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -3,6 +3,7 @@ #include "qemu/processor.h" #include "qemu/atomic.h" +#include "qemu/clang-tsa.h" typedef struct QemuCond QemuCond; typedef struct QemuSemaphore QemuSemaphore; @@ -24,9 +25,12 @@ typedef struct QemuThread QemuThread; void qemu_mutex_init(QemuMutex *mutex); void qemu_mutex_destroy(QemuMutex *mutex); -int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line); -void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line); -void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line); +int TSA_NO_TSA qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, + const int line); +void TSA_NO_TSA qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, + const int line); +void TSA_NO_TSA qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, + const int line); void qemu_rec_mutex_init(QemuRecMutex *mutex); void qemu_rec_mutex_destroy(QemuRecMutex *mutex); @@ -153,8 +157,8 @@ void qemu_cond_destroy(QemuCond *cond); */ void qemu_cond_signal(QemuCond *cond); void qemu_cond_broadcast(QemuCond *cond); -void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, - const char *file, const int line); +void TSA_NO_TSA qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, + const char *file, const int line); bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, const char *file, const int line); diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index bae938c670..2dd1069cd3 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -223,7 +223,7 @@ void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, con error_exit(err, __func__); } -static bool +static bool TSA_NO_TSA qemu_cond_timedwait_ts(QemuCond *cond, QemuMutex *mutex, struct timespec *ts, const char *file, const int line) { From e022d9cab70f02f7a8fb5fd9c619f46ac877dc4e Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Tue, 17 Jan 2023 08:52:02 -0500 Subject: [PATCH 794/814] bsd-user/mmap: use TSA_NO_TSA to suppress clang TSA warnings in FreeBSD FreeBSD implements pthread headers using TSA (thread safety analysis) annotations, therefore when an application is compiled with -Wthread-safety there are some locking/annotation requirements that the user of the pthread API has to follow. This will also be the case in QEMU, since bsd-user/mmap.c uses the pthread API. Therefore when building it with -Wthread-safety the compiler will throw warnings because the functions are not properly annotated. We need TSA to be enabled because it ensures that the critical sections of an annotated variable are properly locked. In order to make the compiler happy and avoid adding all the necessary macros to all callers (lock functions should use TSA_ACQUIRE, while unlock TSA_RELEASE, and this applies to all users of pthread_mutex_lock and pthread_mutex_unlock), simply use TSA_NO_TSA to supppress such warnings. Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20230117135203.3049709-3-eesposit@redhat.com> Reviewed-by: Warner Losh Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- bsd-user/qemu.h | 5 +++-- include/exec/exec-all.h | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 0ceecfb6df..4e7b8b1c06 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -36,6 +36,7 @@ extern char **environ; #include "target_os_signal.h" #include "target.h" #include "exec/gdbstub.h" +#include "qemu/clang-tsa.h" /* * This struct is used to hold certain information about the image. Basically, @@ -234,8 +235,8 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size); -void mmap_fork_start(void); -void mmap_fork_end(int child); +void TSA_NO_TSA mmap_fork_start(void); +void TSA_NO_TSA mmap_fork_end(int child); /* main.c */ extern char qemu_proc_pathname[]; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 54585a9954..0e36f4d063 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -25,6 +25,7 @@ #include "exec/cpu_ldst.h" #endif #include "qemu/interval-tree.h" +#include "qemu/clang-tsa.h" /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -759,8 +760,8 @@ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, } #if defined(CONFIG_USER_ONLY) -void mmap_lock(void); -void mmap_unlock(void); +void TSA_NO_TSA mmap_lock(void); +void TSA_NO_TSA mmap_unlock(void); bool have_mmap_lock(void); /** From 3d2d4cc5a23229088528f9451518f12dea9a7285 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 17 Jan 2023 08:52:03 -0500 Subject: [PATCH 795/814] configure: Enable -Wthread-safety if present This enables clang's thread safety analysis (TSA), which we'll use to statically check the block graph locking. Signed-off-by: Kevin Wolf Message-Id: <20221207131838.239125-9-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Signed-off-by: Kevin Wolf Message-Id: <20230117135203.3049709-4-eesposit@redhat.com> Signed-off-by: Kevin Wolf --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 00415f0b48..cf6db3d551 100755 --- a/configure +++ b/configure @@ -1184,6 +1184,7 @@ add_to warn_flags -Wendif-labels add_to warn_flags -Wexpansion-to-defined add_to warn_flags -Wimplicit-fallthrough=2 add_to warn_flags -Wmissing-format-attribute +add_to warn_flags -Wthread-safety nowarn_flags= add_to nowarn_flags -Wno-initializer-overrides From 1e84cf79573e364075d6e63a4b00f7dc5f8aa924 Mon Sep 17 00:00:00 2001 From: Hanna Czenczek Date: Mon, 6 Feb 2023 14:29:49 +0100 Subject: [PATCH 796/814] curl: Fix error path in curl_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit g_hash_table_destroy() and g_hash_table_foreach_remove() (called by curl_drop_all_sockets()) both require the table to be non-NULL, or will print assertion failures (just print, no abort). There are several paths in curl_open() that can lead to the out_noclean label without s->sockets being allocated, so clean it only if it has been allocated. Example reproducer: $ qemu-img info -f http '' qemu-img: GLib: g_hash_table_foreach_remove: assertion 'hash_table != NULL' failed qemu-img: GLib: g_hash_table_destroy: assertion 'hash_table != NULL' failed qemu-img: Could not open '': http curl driver cannot handle the URL '' (does not start with 'http://') Closes: https://gitlab.com/qemu-project/qemu/-/issues/1475 Suggested-by: Daniel P. Berrangé Signed-off-by: Hanna Czenczek Message-Id: <20230206132949.92917-1-hreitz@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/curl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/block/curl.c b/block/curl.c index cbada22e9e..ba9977af5a 100644 --- a/block/curl.c +++ b/block/curl.c @@ -850,8 +850,10 @@ out_noclean: g_free(s->username); g_free(s->proxyusername); g_free(s->proxypassword); - curl_drop_all_sockets(s->sockets); - g_hash_table_destroy(s->sockets); + if (s->sockets) { + curl_drop_all_sockets(s->sockets); + g_hash_table_destroy(s->sockets); + } qemu_opts_del(opts); return -EINVAL; } From d6ee2e324ec26a02776d90125e3a55454f0ca57e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:20 +0100 Subject: [PATCH 797/814] block-coroutine-wrapper: Introduce no_co_wrapper Some functions must not be called from coroutine context. The common pattern to use them anyway from a coroutine is running them in a BH and letting the calling coroutine yield to be woken up when the BH is completed. Instead of manually writing such wrappers, add support for generating them to block-coroutine-wrapper. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-2-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- include/block/block-common.h | 14 +++++ scripts/block-coroutine-wrapper.py | 83 ++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/include/block/block-common.h b/include/block/block-common.h index 469300fe8d..b5122ef8ab 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -54,6 +54,20 @@ #define co_wrapper_bdrv_rdlock no_coroutine_fn #define co_wrapper_mixed_bdrv_rdlock no_coroutine_fn coroutine_mixed_fn +/* + * no_co_wrapper: Function specifier used by block-coroutine-wrapper.py + * + * Function specifier which does nothing but mark functions to be generated by + * scripts/block-coroutine-wrapper.py. + * + * A no_co_wrapper function declaration creates a coroutine_fn wrapper around + * functions that must not be called in coroutine context. It achieves this by + * scheduling a BH in the bottom half that runs the respective non-coroutine + * function. The coroutine yields after scheduling the BH and is reentered when + * the wrapped function returns. + */ +#define no_co_wrapper + #include "block/blockjob.h" /* block.c */ diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index e82b648127..60e9b3107c 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -63,8 +63,8 @@ class ParamDecl: class FuncDecl: - def __init__(self, return_type: str, name: str, args: str, - variant: str) -> None: + def __init__(self, wrapper_type: str, return_type: str, name: str, + args: str, variant: str) -> None: self.return_type = return_type.strip() self.name = name.strip() self.struct_name = snake_to_camel(self.name) @@ -72,8 +72,21 @@ class FuncDecl: self.create_only_co = 'mixed' not in variant self.graph_rdlock = 'bdrv_rdlock' in variant - subsystem, subname = self.name.split('_', 1) - self.co_name = f'{subsystem}_co_{subname}' + self.wrapper_type = wrapper_type + + if wrapper_type == 'co': + subsystem, subname = self.name.split('_', 1) + self.target_name = f'{subsystem}_co_{subname}' + else: + assert wrapper_type == 'no_co' + subsystem, co_infix, subname = self.name.split('_', 2) + if co_infix != 'co': + raise ValueError(f"Invalid no_co function name: {self.name}") + if not self.create_only_co: + raise ValueError(f"no_co function can't be mixed: {self.name}") + if self.graph_rdlock: + raise ValueError(f"no_co function can't be rdlock: {self.name}") + self.target_name = f'{subsystem}_{subname}' t = self.args[0].type if t == 'BlockDriverState *': @@ -105,7 +118,8 @@ class FuncDecl: # Match wrappers declared with a co_wrapper mark func_decl_re = re.compile(r'^(?P[a-zA-Z][a-zA-Z0-9_]* [\*]?)' - r'\s*co_wrapper' + r'(\s*coroutine_fn)?' + r'\s*(?P(no_)?co)_wrapper' r'(?P(_[a-z][a-z0-9_]*)?)\s*' r'(?P[a-z][a-z0-9_]*)' r'\((?P[^)]*)\);$', re.MULTILINE) @@ -113,7 +127,8 @@ func_decl_re = re.compile(r'^(?P[a-zA-Z][a-zA-Z0-9_]* [\*]?)' def func_decl_iter(text: str) -> Iterator: for m in func_decl_re.finditer(text): - yield FuncDecl(return_type=m.group('return_type'), + yield FuncDecl(wrapper_type=m.group('wrapper_type'), + return_type=m.group('return_type'), name=m.group('wrapper_name'), args=m.group('args'), variant=m.group('variant')) @@ -133,7 +148,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: """ Checks if we are already in coroutine """ - name = func.co_name + name = func.target_name struct_name = func.struct_name graph_assume_lock = 'assume_graph_lock();' if func.graph_rdlock else '' @@ -163,7 +178,7 @@ def create_co_wrapper(func: FuncDecl) -> str: """ Assumes we are not in coroutine, and creates one """ - name = func.co_name + name = func.target_name struct_name = func.struct_name return f"""\ {func.return_type} {func.name}({ func.gen_list('{decl}') }) @@ -183,10 +198,11 @@ def create_co_wrapper(func: FuncDecl) -> str: }}""" -def gen_wrapper(func: FuncDecl) -> str: +def gen_co_wrapper(func: FuncDecl) -> str: assert not '_co_' in func.name + assert func.wrapper_type == 'co' - name = func.co_name + name = func.target_name struct_name = func.struct_name graph_lock='' @@ -225,11 +241,56 @@ static void coroutine_fn {name}_entry(void *opaque) {creation_function(func)}""" +def gen_no_co_wrapper(func: FuncDecl) -> str: + assert '_co_' in func.name + assert func.wrapper_type == 'no_co' + + name = func.target_name + struct_name = func.struct_name + + return f"""\ +/* + * Wrappers for {name} + */ + +typedef struct {struct_name} {{ + Coroutine *co; + {func.return_field} +{ func.gen_block(' {decl};') } +}} {struct_name}; + +static void {name}_bh(void *opaque) +{{ + {struct_name} *s = opaque; + + {func.get_result}{name}({ func.gen_list('s->{name}') }); + + aio_co_wake(s->co); +}} + +{func.return_type} coroutine_fn {func.name}({ func.gen_list('{decl}') }) +{{ + {struct_name} s = {{ + .co = qemu_coroutine_self(), +{ func.gen_block(' .{name} = {name},') } + }}; + assert(qemu_in_coroutine()); + + aio_bh_schedule_oneshot(qemu_get_aio_context(), {name}_bh, &s); + qemu_coroutine_yield(); + + {func.ret} +}}""" + + def gen_wrappers(input_code: str) -> str: res = '' for func in func_decl_iter(input_code): res += '\n\n\n' - res += gen_wrapper(func) + if func.wrapper_type == 'co': + res += gen_co_wrapper(func) + else: + res += gen_no_co_wrapper(func) return res From 4bee90e9da3c58b09d4df949d9c64043133e4181 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:21 +0100 Subject: [PATCH 798/814] block: Create no_co_wrappers for open functions Images can't be opened in coroutine context because opening needs to change the block graph. Add no_co_wrappers so that coroutines have a simple way of opening images in a BH instead. At the same time, mark the wrapped functions as no_coroutine_fn. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-3-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/meson.build | 1 + include/block/block-global-state.h | 35 +++++++++++++++------ include/sysemu/block-backend-global-state.h | 21 ++++++++++--- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/block/meson.build b/block/meson.build index 3662852dc2..382bec0e7d 100644 --- a/block/meson.build +++ b/block/meson.build @@ -141,6 +141,7 @@ block_gen_c = custom_target('block-gen.c', '../include/block/dirty-bitmap.h', '../include/block/block_int-io.h', '../include/block/block-global-state.h', + '../include/sysemu/block-backend-global-state.h', '../include/sysemu/block-backend-io.h', 'coroutines.h' ), diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index a38f86dc15..447176414e 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -77,16 +77,26 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags, Error **errp); int bdrv_drop_filter(BlockDriverState *bs, Error **errp); -BdrvChild *bdrv_open_child(const char *filename, - QDict *options, const char *bdref_key, - BlockDriverState *parent, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - bool allow_none, Error **errp); +BdrvChild * no_coroutine_fn +bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, + BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp); + +BdrvChild * coroutine_fn no_co_wrapper +bdrv_co_open_child(const char *filename, QDict *options, const char *bdref_key, + BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp); + int bdrv_open_file_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, Error **errp); -BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); + +BlockDriverState * no_coroutine_fn +bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); + +BlockDriverState * coroutine_fn no_co_wrapper +bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp); + int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp); int bdrv_set_backing_hd_drained(BlockDriverState *bs, @@ -94,8 +104,15 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, const char *bdref_key, Error **errp); -BlockDriverState *bdrv_open(const char *filename, const char *reference, - QDict *options, int flags, Error **errp); + +BlockDriverState * no_coroutine_fn +bdrv_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + +BlockDriverState * coroutine_fn no_co_wrapper +bdrv_co_open(const char *filename, const char *reference, + QDict *options, int flags, Error **errp); + BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, const char *node_name, QDict *options, int flags, diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h index 6858e39cb6..2b6d27db7c 100644 --- a/include/sysemu/block-backend-global-state.h +++ b/include/sysemu/block-backend-global-state.h @@ -23,10 +23,23 @@ */ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm); -BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, - uint64_t shared_perm, Error **errp); -BlockBackend *blk_new_open(const char *filename, const char *reference, - QDict *options, int flags, Error **errp); + +BlockBackend * no_coroutine_fn +blk_new_with_bs(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, + Error **errp); + +BlockBackend * coroutine_fn no_co_wrapper +blk_co_new_with_bs(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, + Error **errp); + +BlockBackend * no_coroutine_fn +blk_new_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + +BlockBackend * coroutine_fn no_co_wrapper +blk_co_new_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + int blk_get_refcnt(BlockBackend *blk); void blk_ref(BlockBackend *blk); void blk_unref(BlockBackend *blk); From 91817e9c58687f44a4d4d2ee39b88cb778d228a8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:22 +0100 Subject: [PATCH 799/814] luks: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-4-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/crypto.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index b70cec97c7..72ac30568c 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -314,19 +314,18 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, } -static int block_crypto_co_create_generic(BlockDriverState *bs, - int64_t size, - QCryptoBlockCreateOptions *opts, - PreallocMode prealloc, - Error **errp) +static int coroutine_fn +block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, + QCryptoBlockCreateOptions *opts, + PreallocMode prealloc, Error **errp) { int ret; BlockBackend *blk; QCryptoBlock *crypto = NULL; struct BlockCryptoCreateData data; - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto cleanup; @@ -639,7 +638,7 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); luks_opts = &create_options->u.luks; - bs = bdrv_open_blockdev_ref(luks_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); if (bs == NULL) { return -EIO; } @@ -708,8 +707,8 @@ static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (!bs) { ret = -EINVAL; goto fail; From 48a4e92d3c8458cd5ab272790dc6fd884c58e206 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:23 +0100 Subject: [PATCH 800/814] parallels: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-5-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/parallels.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index bbea2f2221..d4378e09de 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -565,13 +565,13 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(parallels_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(parallels_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -651,8 +651,8 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, goto done; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto done; From 5b9d79b62dcee57c9f0f0a5b34eea2bbb1f4e8d2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:24 +0100 Subject: [PATCH 801/814] qcow: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-6-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/qcow.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index 5f0801f545..20c53b447b 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -833,13 +833,13 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(qcow_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qcow_opts->file, errp); if (bs == NULL) { return -EIO; } - qcow_blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + qcow_blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); if (!qcow_blk) { ret = -EPERM; goto exit; @@ -978,8 +978,8 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; From ecbc57caba986d7ac0d5ecb75cc72cdfe3602f51 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:25 +0100 Subject: [PATCH 802/814] qcow2: Fix open/create to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine, as does qcow2_do_open(). Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-7-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/qcow2.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 21aa4c6b7a..ee0e5b45cc 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1617,9 +1617,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (open_data_file) { /* Open external data file */ - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, - &child_of_bds, BDRV_CHILD_DATA, - true, errp); + s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs, + &child_of_bds, BDRV_CHILD_DATA, + true, errp); if (*errp) { ret = -EINVAL; goto fail; @@ -1627,9 +1627,10 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { if (!s->data_file && s->image_data_file) { - s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_of_bds, - BDRV_CHILD_DATA, false, errp); + s->data_file = bdrv_co_open_child(s->image_data_file, options, + "data-file", bs, + &child_of_bds, + BDRV_CHILD_DATA, false, errp); if (!s->data_file) { ret = -EINVAL; goto fail; @@ -3454,7 +3455,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2); qcow2_opts = &create_options->u.qcow2; - bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qcow2_opts->file, errp); if (bs == NULL) { return -EIO; } @@ -3596,7 +3597,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) ret = -EINVAL; goto out; } - data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp); + data_bs = bdrv_co_open_blockdev_ref(qcow2_opts->data_file, errp); if (data_bs == NULL) { ret = -EIO; goto out; @@ -3629,8 +3630,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Create BlockBackend to write to the image */ - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -3712,9 +3713,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (data_bs) { qdict_put_str(options, "data-file", data_bs->node_name); } - blk = blk_new_open(NULL, NULL, options, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, - errp); + blk = blk_co_new_open(NULL, NULL, options, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, + errp); if (blk == NULL) { ret = -EIO; goto out; @@ -3793,9 +3794,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (data_bs) { qdict_put_str(options, "data-file", data_bs->node_name); } - blk = blk_new_open(NULL, NULL, options, - BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, - errp); + blk = blk_co_new_open(NULL, NULL, options, + BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, + errp); if (blk == NULL) { ret = -EIO; goto out; @@ -3877,8 +3878,8 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, goto finish; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto finish; @@ -3892,9 +3893,9 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, goto finish; } - data_bs = bdrv_open(val, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, - errp); + data_bs = bdrv_co_open(val, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); if (data_bs == NULL) { ret = -EIO; goto finish; From 0b1e95cf46f7f43a39b5c4043b399b8ec29bd440 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:26 +0100 Subject: [PATCH 803/814] qed: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-8-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/qed.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/qed.c b/block/qed.c index 4473465bba..175a46c67b 100644 --- a/block/qed.c +++ b/block/qed.c @@ -676,13 +676,13 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(qed_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qed_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -783,8 +783,8 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; From 13dd6327efb565678bcfe14270dc3b6f7859237c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:27 +0100 Subject: [PATCH 804/814] vdi: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-9-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/vdi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 9c8736b26f..27db67d493 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -800,14 +800,14 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, } /* Create BlockBackend to write to the image */ - bs_file = bdrv_open_blockdev_ref(vdi_opts->file, errp); + bs_file = bdrv_co_open_blockdev_ref(vdi_opts->file, errp); if (!bs_file) { ret = -EIO; goto exit; } - blk = blk_new_with_bs(bs_file, BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + blk = blk_co_new_with_bs(bs_file, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); if (!blk) { ret = -EPERM; goto exit; @@ -940,8 +940,8 @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, goto done; } - bs_file = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs_file = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (!bs_file) { ret = -EIO; goto done; From 41e089cbe9966a9459aabd0f754f65e2619391ef Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:28 +0100 Subject: [PATCH 805/814] vhdx: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-10-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/vhdx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/vhdx.c b/block/vhdx.c index ef1f65d917..59fbdb413b 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1991,13 +1991,13 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(vhdx_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(vhdx_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto delete_and_exit; @@ -2090,8 +2090,8 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; From 882f202e9da82369521d4b7a65694571c35e20f1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:29 +0100 Subject: [PATCH 806/814] vmdk: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-11-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/vmdk.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 5b0eae877e..171c9272ca 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2299,9 +2299,9 @@ static int coroutine_fn vmdk_create_extent(const char *filename, goto exit; } - blk = blk_new_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, - errp); + blk = blk_co_new_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); if (blk == NULL) { ret = -EIO; goto exit; @@ -2518,8 +2518,8 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, } assert(full_backing); - backing = blk_new_open(full_backing, NULL, NULL, - BDRV_O_NO_BACKING, errp); + backing = blk_co_new_open(full_backing, NULL, NULL, + BDRV_O_NO_BACKING, errp); g_free(full_backing); if (backing == NULL) { ret = -EIO; @@ -2781,7 +2781,7 @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, BlockdevCreateOptionsVmdk *opts = opaque; if (idx == 0) { - bs = bdrv_open_blockdev_ref(opts->file, errp); + bs = bdrv_co_open_blockdev_ref(opts->file, errp); } else { int i; BlockdevRefList *list = opts->extents; @@ -2796,14 +2796,16 @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, error_setg(errp, "Extent [%d] not specified", idx - 1); return NULL; } - bs = bdrv_open_blockdev_ref(list->value, errp); + bs = bdrv_co_open_blockdev_ref(list->value, errp); } if (!bs) { return NULL; } - blk = blk_new_with_bs(bs, - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + blk = blk_co_new_with_bs(bs, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | + BLK_PERM_RESIZE, + BLK_PERM_ALL, + errp); if (!blk) { return NULL; } From 6ef028519b02fe64bdd6c87c81fd3ed05054ac55 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:30 +0100 Subject: [PATCH 807/814] vpc: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper .bdrv_co_create implementations run in a coroutine. Therefore they are not allowed to open images directly. Fix the calls to use the corresponding no_co_wrappers instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-12-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/vpc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index cfdea7db80..3c256fc5a4 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1005,13 +1005,13 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(vpc_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(vpc_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -1117,8 +1117,8 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; From be1a732c9a74da9b27884c20e14df608fd100401 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:31 +0100 Subject: [PATCH 808/814] block: Fix bdrv_co_create_opts_simple() to open images with no_co_wrapper bdrv_co_create_opts_simple() runs in a coroutine. Therefore it is not allowed to open images directly. Fix the call to use the corresponding no_co_wrapper instead. Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-13-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index aa9062f2c1..6eac16eac5 100644 --- a/block.c +++ b/block.c @@ -657,8 +657,8 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, options = qdict_new(); qdict_put_str(options, "driver", drv->format_name); - blk = blk_new_open(filename, NULL, options, - BDRV_O_RDWR | BDRV_O_RESIZE, errp); + blk = blk_co_new_open(filename, NULL, options, + BDRV_O_RDWR | BDRV_O_RESIZE, errp); if (!blk) { error_prepend(errp, "Protocol driver '%s' does not support image " "creation, and opening the image failed: ", From 321923010d0e46f265c9a16efc340bf0cb66f785 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 26 Jan 2023 18:24:32 +0100 Subject: [PATCH 809/814] block: Assert non-coroutine context for bdrv_open_inherit() Signed-off-by: Kevin Wolf Message-Id: <20230126172432.436111-14-kwolf@redhat.com> Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index 6eac16eac5..122aa9a9ac 100644 --- a/block.c +++ b/block.c @@ -3807,13 +3807,11 @@ out: * function eventually calls bdrv_refresh_total_sectors() which polls * when called from non-coroutine context. */ -static BlockDriverState *bdrv_open_inherit(const char *filename, - const char *reference, - QDict *options, int flags, - BlockDriverState *parent, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - Error **errp) +static BlockDriverState * no_coroutine_fn +bdrv_open_inherit(const char *filename, const char *reference, QDict *options, + int flags, BlockDriverState *parent, + const BdrvChildClass *child_class, BdrvChildRole child_role, + Error **errp) { int ret; BlockBackend *file = NULL; @@ -3829,6 +3827,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, assert(!child_class || !flags); assert(!child_class == !parent); GLOBAL_STATE_CODE(); + assert(!qemu_in_coroutine()); if (reference) { bool options_non_empty = options ? qdict_size(options) : false; From e7b8d9d038f313c2b9e601609e7d7c3ca6ad0234 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 23 Jan 2023 21:14:31 +0100 Subject: [PATCH 810/814] block: Handle curl 7.55.0, 7.85.0 version changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 7.55.0 deprecates CURLINFO_CONTENT_LENGTH_DOWNLOAD in favour of a *_T version, which returns curl_off_t instead of a double. * 7.85.0 deprecates CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS in favour of *_STR variants, specifying the desired protocols via a string. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1440 Signed-off-by: Anton Johansson Message-Id: <20230123201431.23118-1-anjo@rev.ng> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/curl.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/block/curl.c b/block/curl.c index ba9977af5a..8bb39a134e 100644 --- a/block/curl.c +++ b/block/curl.c @@ -38,8 +38,15 @@ // #define DEBUG_VERBOSE +/* CURL 7.85.0 switches to a string based API for specifying + * the desired protocols. + */ +#if LIBCURL_VERSION_NUM >= 0x075500 +#define PROTOCOLS "HTTP,HTTPS,FTP,FTPS" +#else #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ CURLPROTO_FTP | CURLPROTO_FTPS) +#endif #define CURL_NUM_STATES 8 #define CURL_NUM_ACB 8 @@ -510,9 +517,18 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state) * obscure protocols. For example, do not allow POP3/SMTP/IMAP see * CVE-2013-0249. * - * Restricting protocols is only supported from 7.19.4 upwards. + * Restricting protocols is only supported from 7.19.4 upwards. Note: + * version 7.85.0 deprecates CURLOPT_*PROTOCOLS in favour of a string + * based CURLOPT_*PROTOCOLS_STR API. */ -#if LIBCURL_VERSION_NUM >= 0x071304 +#if LIBCURL_VERSION_NUM >= 0x075500 + if (curl_easy_setopt(state->curl, + CURLOPT_PROTOCOLS_STR, PROTOCOLS) || + curl_easy_setopt(state->curl, + CURLOPT_REDIR_PROTOCOLS_STR, PROTOCOLS)) { + goto err; + } +#elif LIBCURL_VERSION_NUM >= 0x071304 if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) || curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) { goto err; @@ -670,7 +686,12 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, const char *file; const char *cookie; const char *cookie_secret; - double d; + /* CURL >= 7.55.0 uses curl_off_t for content length instead of a double */ +#if LIBCURL_VERSION_NUM >= 0x073700 + curl_off_t cl; +#else + double cl; +#endif const char *secretid; const char *protocol_delimiter; int ret; @@ -797,27 +818,36 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } if (curl_easy_perform(state->curl)) goto out; - if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { + /* CURL 7.55.0 deprecates CURLINFO_CONTENT_LENGTH_DOWNLOAD in favour of + * the *_T version which returns a more sensible type for content length. + */ +#if LIBCURL_VERSION_NUM >= 0x073700 + if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl)) { goto out; } +#else + if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl)) { + goto out; + } +#endif /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not * know or the size is zero. From 7.19.4 CURL returns -1 if size is not * known and zero if it is really zero-length file. */ #if LIBCURL_VERSION_NUM >= 0x071304 - if (d < 0) { + if (cl < 0) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Server didn't report file size."); goto out; } #else - if (d <= 0) { + if (cl <= 0) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Unknown file size or zero-length file."); goto out; } #endif - s->len = d; + s->len = cl; if ((!strncasecmp(s->url, "http://", strlen("http://")) || !strncasecmp(s->url, "https://", strlen("https://"))) From 60d90bf43c169b9d1dbcb17ed794b7b02c6862b1 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 14 Feb 2023 18:16:21 +0100 Subject: [PATCH 811/814] block: temporarily hold the new AioContext of bs_top in bdrv_append() bdrv_append() is called with bs_top AioContext held, but bdrv_attach_child_noperm() could change the AioContext of bs_top. bdrv_replace_node_noperm() calls bdrv_drained_begin() starting from commit 2398747128 ("block: Don't poll in bdrv_replace_child_noperm()"). bdrv_drained_begin() can call BDRV_POLL_WHILE that assumes the new lock is taken, so let's temporarily hold the new AioContext to prevent QEMU from failing in BDRV_POLL_WHILE when it tries to release the wrong AioContext. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2168209 Reported-by: Aihua Liang Signed-off-by: Stefano Garzarella Message-Id: <20230214171621.11574-1-sgarzare@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/block.c b/block.c index 122aa9a9ac..0c807d15cd 100644 --- a/block.c +++ b/block.c @@ -5265,6 +5265,8 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp) * child. * * This function does not create any image files. + * + * The caller must hold the AioContext lock for @bs_top. */ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, Error **errp) @@ -5272,11 +5274,14 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, int ret; BdrvChild *child; Transaction *tran = tran_new(); + AioContext *old_context, *new_context = NULL; GLOBAL_STATE_CODE(); assert(!bs_new->backing); + old_context = bdrv_get_aio_context(bs_top); + child = bdrv_attach_child_noperm(bs_new, bs_top, "backing", &child_of_bds, bdrv_backing_role(bs_new), tran, errp); @@ -5285,6 +5290,19 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, goto out; } + /* + * bdrv_attach_child_noperm could change the AioContext of bs_top. + * bdrv_replace_node_noperm calls bdrv_drained_begin, so let's temporarily + * hold the new AioContext, since bdrv_drained_begin calls BDRV_POLL_WHILE + * that assumes the new lock is taken. + */ + new_context = bdrv_get_aio_context(bs_top); + + if (old_context != new_context) { + aio_context_release(old_context); + aio_context_acquire(new_context); + } + ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp); if (ret < 0) { goto out; @@ -5296,6 +5314,11 @@ out: bdrv_refresh_limits(bs_top, NULL, NULL); + if (new_context && old_context != new_context) { + aio_context_release(new_context); + aio_context_acquire(old_context); + } + return ret; } From 167643ff5e77bdfa3d2867f2e2469741484bd63f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 14 Feb 2023 21:28:48 +0300 Subject: [PATCH 812/814] MAINTAINERS: drop Vladimir from parallels block driver I have to admit this is out of my scope now. Still feel free to Cc me directly if my help is needed :) Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20230214182848.1564714-1-vsementsov@yandex-team.ru> Signed-off-by: Kevin Wolf --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index fd54c1f140..65ee4c31b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3579,13 +3579,11 @@ F: block/dmg.c parallels M: Stefan Hajnoczi M: Denis V. Lunev -M: Vladimir Sementsov-Ogievskiy L: qemu-block@nongnu.org S: Supported F: block/parallels.c F: block/parallels-ext.c F: docs/interop/parallels.txt -T: git https://gitlab.com/vsementsov/qemu.git block qed M: Stefan Hajnoczi From 005ee3cdc79e05b7691c8ce078c147c1f9336814 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Thu, 9 Feb 2023 10:45:22 -0500 Subject: [PATCH 813/814] block/file-posix: don't use functions calling AIO_WAIT_WHILE in worker threads When calling bdrv_getlength() in handle_aiocb_write_zeroes(), the function creates a new coroutine and then waits that it finishes using AIO_WAIT_WHILE. The problem is that this function could also run in a worker thread, that has a different AioContext from main loop and iothreads, therefore in AIO_WAIT_WHILE we will have in_aio_context_home_thread(ctx) == false and therefore assert(qemu_get_current_aio_context() == qemu_get_aio_context()); in the else branch will fail, crashing QEMU. Aside from that, bdrv_getlength() is wrong also conceptually, because it reads the BDS graph from another thread and is not protected by any lock. Replace it with raw_co_getlength, that doesn't create a coroutine and doesn't read the BDS graph. Reported-by: Ninad Palsule Suggested-by: Kevin Wolf Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20230209154522.1164401-1-eesposit@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- 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 d3073a7caa..9a99111f45 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1738,7 +1738,7 @@ static int handle_aiocb_write_zeroes(void *opaque) #ifdef CONFIG_FALLOCATE /* Last resort: we are trying to extend the file with zeroed data. This * can be done via fallocate(fd, 0) */ - len = bdrv_getlength(aiocb->bs); + len = raw_co_getlength(aiocb->bs); if (s->has_fallocate && len >= 0 && aiocb->aio_offset >= len) { int ret = do_fallocate(s->fd, 0, aiocb->aio_offset, aiocb->aio_nbytes); if (ret == 0 || ret != -ENOTSUP) { From a4d5224c2cb650b5a401d626d3f36e42e6987aa7 Mon Sep 17 00:00:00 2001 From: Andrey Zhadchenko Date: Thu, 2 Feb 2023 21:15:23 +0300 Subject: [PATCH 814/814] hbitmap: fix hbitmap_status() return value for first dirty bit case The last return statement should return true, as we already evaluated that start == next_dirty Also, fix hbitmap_status() description in header Cc: qemu-stable@nongnu.org Fixes: a6426475a75 ("block/dirty-bitmap: introduce bdrv_dirty_bitmap_status()") Signed-off-by: Andrey Zhadchenko Message-Id: <20230202181523.423131-1-andrey.zhadchenko@virtuozzo.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/qemu/hbitmap.h | 2 +- util/hbitmap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index af4e4ab746..8136e33674 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -330,7 +330,7 @@ bool hbitmap_next_dirty_area(const HBitmap *hb, int64_t start, int64_t end, int64_t *dirty_start, int64_t *dirty_count); /* - * bdrv_dirty_bitmap_status: + * hbitmap_status: * @hb: The HBitmap to operate on * @start: The bit to start from * @count: Number of bits to proceed diff --git a/util/hbitmap.c b/util/hbitmap.c index 297db35fb1..6d6e1b595d 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -331,7 +331,7 @@ bool hbitmap_status(const HBitmap *hb, int64_t start, int64_t count, assert(next_zero > start); *pnum = next_zero - start; - return false; + return true; } bool hbitmap_empty(const HBitmap *hb)