From 47c66009ab793241e8210b3018c77a9ce9506aa8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 3 Mar 2018 08:33:10 +0100 Subject: qom: introduce object_class_get_list_sorted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify half a dozen copies of very similar code (the only difference being whether comparisons were case-sensitive) and use it also in Tricore, which did not do any sorting of CPU model names. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- include/qom/object.h | 11 +++++++++++ qdev-monitor.c | 9 +-------- qom/object.c | 13 +++++++++++++ target/alpha/cpu.c | 15 +-------------- target/hppa/cpu.c | 15 +-------------- target/lm32/cpu.c | 15 +-------------- target/sh4/cpu.c | 15 +-------------- target/tricore/helper.c | 2 +- 8 files changed, 30 insertions(+), 65 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 4f07090db0..96ce81bc5e 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -913,6 +913,17 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), GSList *object_class_get_list(const char *implements_type, bool include_abstract); +/** + * object_class_get_list_sorted: + * @implements_type: The type to filter for, including its derivatives. + * @include_abstract: Whether to include abstract classes. + * + * Returns: A singly-linked list of the classes in alphabetical + * case-insensitive order. + */ +GSList *object_class_get_list_sorted(const char *implements_type, + bool include_abstract); + /** * object_ref: * @obj: the object diff --git a/qdev-monitor.c b/qdev-monitor.c index b7e3291f8b..61e0300991 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -122,12 +122,6 @@ static void qdev_print_devinfo(DeviceClass *dc) error_printf("\n"); } -static gint devinfo_cmp(gconstpointer a, gconstpointer b) -{ - return strcasecmp(object_class_get_name((ObjectClass *)a), - object_class_get_name((ObjectClass *)b)); -} - static void qdev_print_devinfos(bool show_no_user) { static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = { @@ -146,8 +140,7 @@ static void qdev_print_devinfos(bool show_no_user) int i; bool cat_printed; - list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false), - devinfo_cmp); + list = object_class_get_list_sorted(TYPE_DEVICE, false); for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) { cat_printed = false; diff --git a/qom/object.c b/qom/object.c index 755ad03819..6088f55943 100644 --- a/qom/object.c +++ b/qom/object.c @@ -891,6 +891,19 @@ GSList *object_class_get_list(const char *implements_type, return list; } +static gint object_class_cmp(gconstpointer a, gconstpointer b) +{ + return strcasecmp(object_class_get_name((ObjectClass *)a), + object_class_get_name((ObjectClass *)b)); +} + +GSList *object_class_get_list_sorted(const char *implements_type, + bool include_abstract) +{ + return g_slist_sort(object_class_get_list(implements_type, include_abstract), + object_class_cmp); +} + void object_ref(Object *obj) { if (!obj) { diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 55675ce419..b08078e7fc 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -71,18 +71,6 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) acc->parent_realize(dev, errp); } -/* Sort alphabetically by type name. */ -static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - static void alpha_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; @@ -100,8 +88,7 @@ void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) }; GSList *list; - list = object_class_get_list(TYPE_ALPHA_CPU, false); - list = g_slist_sort(list, alpha_cpu_list_compare); + list = object_class_get_list_sorted(TYPE_ALPHA_CPU, false); (*cpu_fprintf)(f, "Available CPUs:\n"); g_slist_foreach(list, alpha_cpu_list_entry, &s); g_slist_free(list); diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 969f628f0a..c261b6b090 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -110,18 +110,6 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp) #endif } -/* Sort hppabetically by type name. */ -static gint hppa_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - static void hppa_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; @@ -138,8 +126,7 @@ void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf) }; GSList *list; - list = object_class_get_list(TYPE_HPPA_CPU, false); - list = g_slist_sort(list, hppa_cpu_list_compare); + list = object_class_get_list_sorted(TYPE_HPPA_CPU, false); (*cpu_fprintf)(f, "Available CPUs:\n"); g_slist_foreach(list, hppa_cpu_list_entry, &s); g_slist_free(list); diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c index 96c2499d0b..0003152469 100644 --- a/target/lm32/cpu.c +++ b/target/lm32/cpu.c @@ -32,18 +32,6 @@ static void lm32_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.pc = value; } -/* Sort alphabetically by type name. */ -static gint lm32_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - static void lm32_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; @@ -65,8 +53,7 @@ void lm32_cpu_list(FILE *f, fprintf_function cpu_fprintf) }; GSList *list; - list = object_class_get_list(TYPE_LM32_CPU, false); - list = g_slist_sort(list, lm32_cpu_list_compare); + list = object_class_get_list_sorted(TYPE_LM32_CPU, false); (*cpu_fprintf)(f, "Available CPUs:\n"); g_slist_foreach(list, lm32_cpu_list_entry, &s); g_slist_free(list); diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 6302cfda3a..541ffc2d97 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -85,18 +85,6 @@ typedef struct SuperHCPUListState { FILE *file; } SuperHCPUListState; -/* Sort alphabetically by type name. */ -static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - static void superh_cpu_list_entry(gpointer data, gpointer user_data) { SuperHCPUListState *s = user_data; @@ -114,8 +102,7 @@ void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) }; GSList *list; - list = object_class_get_list(TYPE_SUPERH_CPU, false); - list = g_slist_sort(list, superh_cpu_list_compare); + list = object_class_get_list_sorted(TYPE_SUPERH_CPU, false); g_slist_foreach(list, superh_cpu_list_entry, &s); g_slist_free(list); } diff --git a/target/tricore/helper.c b/target/tricore/helper.c index 45276d3782..dad7eea085 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -101,7 +101,7 @@ void tricore_cpu_list(FILE *f, fprintf_function cpu_fprintf) }; GSList *list; - list = object_class_get_list(TYPE_TRICORE_CPU, false); + list = object_class_get_list_sorted(TYPE_TRICORE_CPU, false); (*cpu_fprintf)(f, "Available CPUs:\n"); g_slist_foreach(list, tricore_cpu_list_entry, &s); g_slist_free(list); -- cgit v1.2.1 From 52310c3fa7dc854dd2376ae8a518141abcdb78f3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Mar 2018 10:30:50 +0100 Subject: net: allow using any PCI NICs in -net or -nic Remove the hard-coded list of PCI NIC names; instead, fill an array using all PCI devices listed under DEVICE_CATEGORY_NETWORK. Keep the old shortcut "virtio" for virtio-net-pci. Suggested-by: Thomas Huth Reviewed-by: Thomas Huth Reviewed-by: Jason Wang Signed-off-by: Paolo Bonzini --- hw/pci/pci.c | 61 +++++++++++++++++++++++++++++------------------------------ hw/ppc/e500.c | 2 +- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2174c254eb..67a3f72bd6 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1815,49 +1815,48 @@ PciInfoList *qmp_query_pci(Error **errp) return head; } -static const char * const pci_nic_models[] = { - "ne2k_pci", - "i82551", - "i82557b", - "i82559er", - "rtl8139", - "e1000", - "pcnet", - "virtio", - "sungem", - NULL -}; - -static const char * const pci_nic_names[] = { - "ne2k_pci", - "i82551", - "i82557b", - "i82559er", - "rtl8139", - "e1000", - "pcnet", - "virtio-net-pci", - "sungem", - NULL -}; - /* Initialize a PCI NIC. */ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, const char *default_model, const char *default_devaddr) { const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr; + GSList *list; + GPtrArray *pci_nic_models; PCIBus *bus; PCIDevice *pci_dev; DeviceState *dev; int devfn; int i; - if (qemu_show_nic_models(nd->model, pci_nic_models)) { + if (nd->model && !strcmp(nd->model, "virtio")) { + g_free(nd->model); + 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); + g_ptr_array_add(pci_nic_models, (gpointer)name); + } + next = list->next; + g_slist_free_1(list); + list = next; + } + g_ptr_array_add(pci_nic_models, NULL); + + if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) { exit(0); } - i = qemu_find_nic_model(nd, pci_nic_models, default_model); + i = qemu_find_nic_model(nd, (const char **)pci_nic_models->pdata, + default_model); if (i < 0) { exit(1); } @@ -1865,15 +1864,15 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus, bus = pci_get_bus_devfn(&devfn, rootbus, devaddr); if (!bus) { error_report("Invalid PCI device address %s for device %s", - devaddr, pci_nic_names[i]); + devaddr, nd->model); exit(1); } - pci_dev = pci_create(bus, devfn, pci_nic_names[i]); + pci_dev = pci_create(bus, devfn, nd->model); dev = &pci_dev->qdev; qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - + g_ptr_array_free(pci_nic_models, true); return pci_dev; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 43c15d18c4..2238f963c4 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -916,7 +916,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) if (pci_bus) { /* Register network interfaces. */ for (i = 0; i < nb_nics; i++) { - pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL); + pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL); } } -- cgit v1.2.1 From 4b9c264bd286af7d65892821d19e13b17259b6c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Mar 2018 10:29:06 +0100 Subject: q35: change default NIC to e1000e The e1000 NIC is getting old and is not a very good default for a PCIe machine type. Change it to e1000e, which should be supported by a good number of guests. In particular, drivers for 82574 were added first to Linux 2.6.27 (2008) and Windows 2008 R2. This does mean that Windows 2008 will not work anymore with Q35 machine types and a default "-net nic -net xxx" network configuration; it did work before because it does have an AHCI driver. However, Windows 2008 has been declared out of main stream support in 2015. It will get out of extended support in 2020. Windows 2008 R2 has the same end of support dates and, since the two are basically Vista vs. Windows 7, R2 probably is more popular. Reviewed-by: Jason Wang Reviewed-by: Thomas Huth Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 7 ++++--- hw/i386/pc_piix.c | 6 +++++- hw/i386/pc_q35.c | 8 +++++++- include/hw/i386/pc.h | 3 ++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 35fcb6efdf..dc1f535697 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1619,18 +1619,19 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, } } -void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) +void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) { int i; rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; + const char *model = nd->model ? nd->model : pcmc->default_nic_model; - if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) { + if (g_str_equal(model, "ne2k_isa")) { pc_init_ne2k_isa(isa_bus, nd); } else { - pci_nic_init_nofail(nd, pci_bus, "e1000", NULL); + pci_nic_init_nofail(nd, pci_bus, model, NULL); } } rom_reset_order_override(); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 8658bcba63..0f1966d547 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -240,7 +240,7 @@ static void pc_init1(MachineState *machine, pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true, (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4); - pc_nic_init(isa_bus, pci_bus); + pc_nic_init(pcmc, isa_bus, pci_bus); ide_drive_get(hd, ARRAY_SIZE(hd)); if (pcmc->pci_enabled) { @@ -417,6 +417,9 @@ static void pc_xen_hvm_init(MachineState *machine) static void pc_i440fx_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pcmc->default_nic_model = "e1000"; + m->family = "pc_piix"; m->desc = "Standard PC (i440FX + PIIX, 1996)"; m->default_machine_opts = "firmware=bios-256k.bin"; @@ -1114,6 +1117,7 @@ static void isapc_machine_options(MachineClass *m) pcmc->gigabyte_align = false; pcmc->smbios_legacy_mode = true; pcmc->has_reserved_memory = false; + pcmc->default_nic_model = "ne2k_isa"; m->default_cpu_type = X86_CPU_TYPE_NAME("486"); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0c0bc48137..9ae916327e 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -272,7 +272,7 @@ static void pc_q35_init(MachineState *machine) /* the rest devices to which pci devfn is automatically assigned */ pc_vga_init(isa_bus, host_bus); - pc_nic_init(isa_bus, host_bus); + pc_nic_init(pcmc, isa_bus, host_bus); if (pcms->acpi_nvdimm_state.is_enabled) { nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io, @@ -294,6 +294,9 @@ static void pc_q35_init(MachineState *machine) static void pc_q35_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pcmc->default_nic_model = "e1000e"; + m->family = "pc_q35"; m->desc = "Standard PC (Q35 + ICH9, 2009)"; m->units_per_default_bus = 1; @@ -316,7 +319,10 @@ DEFINE_Q35_MACHINE(v2_12, "pc-q35-2.12", NULL, static void pc_q35_2_11_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_2_12_machine_options(m); + pcmc->default_nic_model = "e1000"; m->alias = NULL; SET_MACHINE_COMPAT(m, PC_COMPAT_2_11); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index bb49165fe0..e81654eb7f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -114,6 +114,7 @@ struct PCMachineClass { /* Device configuration: */ bool pci_enabled; bool kvmclock_enabled; + const char *default_nic_model; /* Compat options: */ @@ -248,7 +249,7 @@ void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, BusState *ide0, BusState *ide1, ISADevice *s); -void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); +void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus); void pc_pci_device_init(PCIBus *pci_bus); typedef void (*cpu_set_smm_t)(int smm, void *arg); -- cgit v1.2.1 From d082d16a5c521907190c58cb7e4ff5eed5c48ab1 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 6 Mar 2018 12:44:11 -0300 Subject: scsi-disk.c: consider bl->max_transfer in INQUIRY emulation The calculation of the max_transfer atribute of BlockDriverState makes considerations such as max_segments and transfer_length via the BLKSECTGET ioctl (if available). However, bl->max_transfer isn't considered when emulating the INQUIRY 'Block Limit' response to the scsi-hd devices. This leads to situations where the declared max_sectors from the INQUIRY response is inconsistent with the block limits, which isn't ideal. It can also be misleading to the user that sets /sys/block//queue/max_sectors_kb to a certain value, then finds a different value in the guest OS for the same disk. Following the same logic scsi_read_complete from scsi-generic.c does when patching the response of the Block Limits VPD back to the guest, change the max_io_sectors value of the emulated Block Limits VPD response by considering the blk_get_max_transfer of the related BlockDriverState. Use MIN_NOT_ZERO to be sure that the minimal value is chosen. Given that we're changing max_io_sectors, consider that min_io_sectors and opt_io_sectors can't be greater than the new calculated value. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Fam Zheng Message-Id: <20180306154411.18462-1-danielhb@linux.vnet.ibm.com> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 49d2559d93..c65c1ce56d 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -704,6 +704,21 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) page_code); return -1; } + if (s->qdev.type == TYPE_DISK) { + int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk); + int max_io_sectors_blk = + max_transfer_blk / s->qdev.blocksize; + + max_io_sectors = + MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors); + + /* min_io_size and opt_io_size can't be greater than + * max_io_sectors */ + min_io_size = + MIN_NON_ZERO(min_io_size, max_io_sectors); + opt_io_size = + MIN_NON_ZERO(opt_io_size, max_io_sectors); + } /* required VPD size with unmap support */ buflen = 0x40; memset(outbuf + 4, 0, buflen - 4); -- cgit v1.2.1 From fb8152181db0df60285ec28df1be724632568569 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Feb 2018 12:25:14 +0100 Subject: qemu-doc: update deprecation section to use -nic and -netdev hubport The deprecated SLIRP options -tftp, -bootp, -redir, -smb provide sample replacements that use "-net nic". Suggest "-nic" instead, since we finally have a path towards getting rid of "-net". For "-net vlan" the replacement involves hubport network devices, so mention that too. Cc: Jason Wang Acked-by: Thomas Huth Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 39e38c87ec..918d97c18b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2643,42 +2643,46 @@ combined with ``-vnc tls-creds=tls0' @subsection -tftp (since 2.6.0) -The ``-tftp /some/dir'' argument is replaced by -``-netdev user,id=x,tftp=/some/dir'', either accompanied with -``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +The ``-tftp /some/dir'' argument is replaced by either +``-netdev user,id=x,tftp=/some/dir '' (for pluggable NICs, accompanied +with ``-device ...,netdev=x''), or ``-nic user,tftp=/some/dir'' (for embedded NICs). The new syntax allows different settings to be provided per NIC. @subsection -bootp (since 2.6.0) -The ``-bootp /some/file'' argument is replaced by -``-netdev user,id=x,bootp=/some/file'', either accompanied with -``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +The ``-bootp /some/file'' argument is replaced by either +``-netdev user,id=x,bootp=/some/file '' (for pluggable NICs, accompanied +with ``-device ...,netdev=x''), or ``-nic user,bootp=/some/file'' (for embedded NICs). The new syntax allows different settings to be provided per NIC. @subsection -redir (since 2.6.0) The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport'' argument is -replaced by ``-netdev -user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'', -either accompanied with ``-device ...,netdev=x'' (for pluggable NICs) or -``-net nic,netdev=x'' (for embedded NICs). The new syntax allows different -settings to be provided per NIC. +replaced by either +``-netdev user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'' +(for pluggable NICs, accompanied with ``-device ...,netdev=x'') or +``-nic user,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'' +(for embedded NICs). The new syntax allows different settings to be +provided per NIC. @subsection -smb (since 2.6.0) -The ``-smb /some/dir'' argument is replaced by -``-netdev user,id=x,smb=/some/dir'', either accompanied with -``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +The ``-smb /some/dir'' argument is replaced by either +``-netdev user,id=x,smb=/some/dir '' (for pluggable NICs, accompanied +with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir'' (for embedded NICs). The new syntax allows different settings to be provided per NIC. @subsection -net vlan (since 2.9.0) -The ``-net vlan=NN'' argument is partially replaced with the -new ``-netdev'' argument. The remaining use cases will no -longer be directly supported in QEMU. +The ``-net vlan=NN'' argument was mostly used to attach separate +network backends to different virtual NICs. This is the default +behavior for ``-netdev'' and ``-nic''. You can connect multiple +``-netdev'' and ``-nic'' devices to the same network using the +"hubport" network backend, created with ``-netdev hubport,hubid=NN,...'' +and ``-nic hubport,hubid=NN''. @subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0) -- cgit v1.2.1 From e12c8198cf473afbec3f634a45047067773143a9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 7 Mar 2018 07:56:09 +0100 Subject: qemu-doc: Add the paragraph about the -no-frame deprecation again The section has accidentially been removed while resolving a contextual conflict during a rebase, so add this again. Fixes: f29d4450428fe07e9d6b0655cef2e59bfa0b2ea5 Signed-off-by: Thomas Huth Message-Id: <1520405769-22179-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 918d97c18b..f8da9b8135 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2732,6 +2732,12 @@ filesystem test suite. Also it requires the CAP_DAC_READ_SEARCH capability, which is not the recommended way to run QEMU. This backend should not be used and it will be removed with no replacement. +@subsection -no-frame (since 2.12.0) + +The @code{--no-frame} argument works with SDL 1.2 only. The other user +interfaces never implemented this in the first place. So this will be +removed together with SDL 1.2 support. + @subsection -rtc-td-hack (since 2.12.0) The @code{-rtc-td-hack} option has been replaced by -- cgit v1.2.1 From 0decdfe29ba6e6c9253af342916395b182bd4f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 6 Mar 2018 17:17:28 +0100 Subject: build-sys: make help could have 'modules' target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Available when configure --enable-modules. Signed-off-by: Marc-André Lureau Message-Id: <20180306161728.20890-1-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 9a75c48ae0..5d9ef3b8fd 100644 --- a/Makefile +++ b/Makefile @@ -1046,6 +1046,9 @@ include $(SRC_PATH)/tests/vm/Makefile.include help: @echo 'Generic targets:' @echo ' all - Build all' +ifdef CONFIG_MODULES + @echo ' modules - Build all modules' +endif @echo ' dir/file.o - Build specified target only' @echo ' install - Install QEMU, documentation and tools' @echo ' ctags/TAGS - Generate tags file for editors' -- cgit v1.2.1 From 7eceff5b5a1faa394929cacfd3520caa5b3edf42 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Feb 2018 09:55:12 +0100 Subject: hw: Do not include "sysemu/block-backend.h" if it is not necessary After reviewing a patch from Philippe that removes block-backend.h from hw/lm32/milkymist.c, I noticed that this header is included unnecessarily in a lot of other files, too. Remove those unneeded includes to speed up the compilation process a little bit. Signed-off-by: Thomas Huth Message-Id: <1518684912-31637-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- hw/arm/highbank.c | 1 - hw/arm/msf2-soc.c | 1 - hw/arm/realview.c | 1 - hw/arm/tosa.c | 1 - hw/i386/pc.c | 2 -- hw/i386/pc_piix.c | 1 - hw/ide/ahci-allwinner.c | 1 - hw/ide/cmd646.c | 1 - hw/ide/ich.c | 1 - hw/ide/isa.c | 1 - hw/ide/microdrive.c | 1 - hw/ide/mmio.c | 1 - hw/mips/mips_fulong2e.c | 1 - hw/mips/mips_jazz.c | 1 - hw/ppc/mac_newworld.c | 1 - hw/ppc/mac_oldworld.c | 1 - hw/ppc/prep.c | 1 - hw/scsi/mptendian.c | 1 - hw/sd/core.c | 1 - hw/sparc/sun4m.c | 1 - hw/tricore/tricore_testboard.c | 2 -- 21 files changed, 23 deletions(-) diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 287392bbdc..1742cf6f6c 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -27,7 +27,6 @@ #include "sysemu/kvm.h" #include "sysemu/sysemu.h" #include "hw/boards.h" -#include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index a8ec2cdf36..f68df56b97 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -29,7 +29,6 @@ #include "exec/address-spaces.h" #include "hw/char/serial.h" #include "hw/boards.h" -#include "sysemu/block-backend.h" #include "qemu/cutils.h" #include "hw/arm/msf2-soc.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 87cd1e583c..2139a62e25 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -20,7 +20,6 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/i2c/i2c.h" -#include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index a55b1a369c..7a925fa5e6 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -22,7 +22,6 @@ #include "hw/boards.h" #include "hw/i2c/i2c.h" #include "hw/ssi/ssi.h" -#include "sysemu/block-backend.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index dc1f535697..0c140f4dc7 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -50,8 +50,6 @@ #include "sysemu/qtest.h" #include "kvm_i386.h" #include "hw/xen/xen.h" -#include "sysemu/block-backend.h" -#include "hw/block/block.h" #include "ui/qemu-spice.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0f1966d547..729a0508aa 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -40,7 +40,6 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/arch_init.h" -#include "sysemu/block-backend.h" #include "hw/i2c/smbus.h" #include "hw/xen/xen.h" #include "exec/memory.h" diff --git a/hw/ide/ahci-allwinner.c b/hw/ide/ahci-allwinner.c index c3f1604936..5397483fd8 100644 --- a/hw/ide/ahci-allwinner.c +++ b/hw/ide/ahci-allwinner.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "qemu/error-report.h" -#include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "hw/ide/internal.h" #include "hw/ide/ahci_internal.h" diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 65aff518ec..6bb92d717f 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -26,7 +26,6 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" -#include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" diff --git a/hw/ide/ich.c b/hw/ide/ich.c index c01b24ecbe..134478ebb2 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -65,7 +65,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" -#include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "hw/ide/pci.h" #include "hw/ide/ahci_internal.h" diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 9fb24fc92b..028bd61774 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/isa/isa.h" -#include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "hw/ide/internal.h" diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 58e4f52f7d..34bb98dce8 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pcmcia.h" -#include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "hw/ide/internal.h" diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 6f12f456ed..42fcf139ee 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" -#include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "hw/ide/internal.h" diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index f68c625666..be4f83973d 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -27,7 +27,6 @@ #include "net/net.h" #include "hw/boards.h" #include "hw/i2c/smbus.h" -#include "sysemu/block-backend.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index b09871a814..08e6f620fc 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -41,7 +41,6 @@ #include "hw/timer/i8254.h" #include "hw/display/vga.h" #include "hw/audio/pcspk.h" -#include "sysemu/block-backend.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index a749e2565d..2f5b6f651a 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -69,7 +69,6 @@ #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "hw/usb.h" -#include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "hw/sysbus.h" #include "qemu/cutils.h" diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 935493c966..10e291ca22 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -44,7 +44,6 @@ #include "qemu/error-report.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/cutils.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 096d4d4cfb..c9d8950de7 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -43,7 +43,6 @@ #include "hw/timer/mc146818rtc.h" #include "hw/isa/pc87312.h" #include "hw/net/ne2000-isa.h" -#include "sysemu/block-backend.h" #include "sysemu/arch_init.h" #include "sysemu/kvm.h" #include "sysemu/qtest.h" diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c index 3415229b5e..8ae39a76f4 100644 --- a/hw/scsi/mptendian.c +++ b/hw/scsi/mptendian.c @@ -24,7 +24,6 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "sysemu/dma.h" -#include "sysemu/block-backend.h" #include "hw/pci/msi.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" diff --git a/hw/sd/core.c b/hw/sd/core.c index 3c6eae6c88..820345f704 100644 --- a/hw/sd/core.c +++ b/hw/sd/core.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "hw/qdev-core.h" -#include "sysemu/block-backend.h" #include "hw/sd/sd.h" #include "trace.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 0f5804b3b4..2b8af2c884 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -44,7 +44,6 @@ #include "hw/empty_slot.h" #include "hw/loader.h" #include "elf.h" -#include "sysemu/block-backend.h" #include "trace.h" #include "qemu/cutils.h" diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index ac75eb2128..8e61dfc3e6 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -28,9 +28,7 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" -#include "sysemu/block-backend.h" #include "exec/address-spaces.h" -#include "hw/block/flash.h" #include "elf.h" #include "hw/tricore/tricore.h" #include "qemu/error-report.h" -- cgit v1.2.1 From 205f31a81adbd06830f2048ec00d729ebd67efa6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 22 Feb 2018 15:58:38 -0600 Subject: checkpatch: Exempt long URLs Sometimes, we want to refer to really long URLs, but checkpatch balks, and we have to manually bypass the check. URL shorteners may be nice at reducing long links, but it's hard to guarantee the shortened link will live as long as the real target, and it is also nice to see the original target without having to load the shortened URL through a browser. So exempt a line containing only a URL from the long-line syntax check. Reviewed-by: Stefan Hajnoczi Suggested-by: Peter Maydell Signed-off-by: Eric Blake Message-Id: <20180222215838.18223-1-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d1fe79bcc4..57daae05ea 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1447,9 +1447,10 @@ sub process { # check we are in a valid source file if not then ignore this hunk next if ($realfile !~ /$SrcFile/); -#90 column limit +#90 column limit; exempt URLs, if no other words on line if ($line =~ /^\+/ && !($line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && + !($rawline =~ /^[^[:alnum:]]*https?:\S*$/) && $length > 80) { if ($length > 90) { -- cgit v1.2.1 From c8ca2a23a953bcda04b5e10380f462526ed1ed89 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:12 +0800 Subject: vl: export machine_init_done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have that variable but not exported. Export that so modules can have a way to poke on whether machine init has finished. Meanwhile, set that up even before calling the notifiers, so that notifiers who may depend on this field will get a correct answer. Suggested-by: Paolo Bonzini Reviewed-by: Marc-André Lureau Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-2-peterx@redhat.com> Reviewed-by: Daniel P. Berrangé Acked-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- include/sysemu/sysemu.h | 2 ++ stubs/machine-init-done.c | 2 ++ vl.c | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 356bfdc1c1..2b42151c63 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -88,6 +88,8 @@ void qemu_system_guest_panicked(GuestPanicInformation *info); void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); +extern bool machine_init_done; + void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_remove_machine_init_done_notifier(Notifier *notify); diff --git a/stubs/machine-init-done.c b/stubs/machine-init-done.c index 9a0d62514f..4121f1709b 100644 --- a/stubs/machine-init-done.c +++ b/stubs/machine-init-done.c @@ -2,6 +2,8 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" +bool machine_init_done = true; + void qemu_add_machine_init_done_notifier(Notifier *notify) { } diff --git a/vl.c b/vl.c index 3ef04ce991..26662eb9e7 100644 --- a/vl.c +++ b/vl.c @@ -2696,7 +2696,7 @@ static void qemu_run_exit_notifiers(void) notifier_list_notify(&exit_notifiers, NULL); } -static bool machine_init_done; +bool machine_init_done; void qemu_add_machine_init_done_notifier(Notifier *notify) { @@ -2713,8 +2713,8 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify) static void qemu_run_machine_init_done_notifiers(void) { - notifier_list_notify(&machine_init_done_notifiers, NULL); machine_init_done = true; + notifier_list_notify(&machine_init_done_notifiers, NULL); } static const QEMUOption *lookup_opt(int argc, char **argv, -- cgit v1.2.1 From c863fdec6aff6b5a4ca8fff1537b80d9f8b97726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 Feb 2018 12:13:51 +0000 Subject: chardev: fix handling of EAGAIN for TCP chardev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When this commit was applied commit 9894dc0cdcc397ee5b26370bc53da6d360a363c2 Author: Daniel P. Berrange Date: Tue Jan 19 11:14:29 2016 +0000 char: convert from GIOChannel to QIOChannel The tcp_chr_recv() function was changed to return QIO_CHANNEL_ERR_BLOCK which corresonds to -2. As such the handling for EAGAIN was able to be removed from tcp_chr_read(). Unfortunately in a later commit: commit b6572b4f97a7b126c7b24e165893ed9fe3d72e1f Author: Marc-André Lureau Date: Fri Mar 11 18:55:24 2016 +0100 char: translate from QIOChannel error to errno The tcp_chr_recv() function was changed back to return -1, with errno set to EAGAIN, without also re-addding support for this to tcp_chr_read() Reported-by: Aleksey Kuleshov Signed-off-by: Daniel P. Berrangé Message-Id: <20180222121351.26191-1-berrange@redhat.com> Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index a220803c01..541fcf487d 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -450,7 +450,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) len = s->max_size; } size = tcp_chr_recv(chr, (void *)buf, len); - if (size == 0 || size == -1) { + if (size == 0 || (size == -1 && errno != EAGAIN)) { /* connection closed */ tcp_chr_disconnect(chr); } else if (size > 0) { -- cgit v1.2.1 From 3da9de5ce22125c917f722f13f91a0e3b096a251 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:14 +0800 Subject: chardev: update net listener gcontext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCP chardevs can be using QIO network listeners working in the background when in listening mode. However the network listeners are always running in main context. This can race with chardevs that are running in non-main contexts. To solve this, we need to re-setup the net listeners in tcp_chr_update_read_handler() with the newly cached gcontext. Reviewed-by: Marc-André Lureau Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-4-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 541fcf487d..2475e1d52f 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -423,8 +423,8 @@ static void tcp_chr_disconnect(Chardev *chr) tcp_chr_free_connection(chr); if (s->listener) { - qio_net_listener_set_client_func(s->listener, tcp_chr_accept, - chr, NULL); + qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept, + chr, NULL, chr->gcontext); } update_disconnected_filename(s); if (emit_close) { @@ -560,6 +560,16 @@ static void tcp_chr_update_read_handler(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); + if (s->listener) { + /* + * It's possible that chardev context is changed in + * qemu_chr_be_update_read_handlers(). Reset it for QIO net + * listener if there is. + */ + qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept, + chr, NULL, chr->gcontext); + } + if (!s->connected) { return; } @@ -744,7 +754,8 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc) qio_channel_set_delay(s->ioc, false); } if (s->listener) { - qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); + qio_net_listener_set_client_func_full(s->listener, NULL, NULL, + NULL, chr->gcontext); } if (s->tls_creds) { @@ -825,7 +836,8 @@ static void char_socket_finalize(Object *obj) tcp_chr_reconn_timer_cancel(s); qapi_free_SocketAddress(s->addr); if (s->listener) { - qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); + qio_net_listener_set_client_func_full(s->listener, NULL, NULL, + NULL, chr->gcontext); object_unref(OBJECT(s->listener)); } if (s->tls_creds) { @@ -981,8 +993,10 @@ static void qmp_chardev_open_socket(Chardev *chr, return; } if (!s->ioc) { - qio_net_listener_set_client_func(s->listener, tcp_chr_accept, - chr, NULL); + qio_net_listener_set_client_func_full(s->listener, + tcp_chr_accept, + chr, NULL, + chr->gcontext); } } else if (qemu_chr_wait_connected(chr, errp) < 0) { goto error; -- cgit v1.2.1 From ce1230c054e97932660aecd9ba61ee31d461e339 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:15 +0800 Subject: chardev: allow telnet gsource to switch gcontext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was originally created by qio_channel_add_watch() so it's always assigning the task to main context. Now we use the new API called qio_channel_add_watch_source() so that we get the GSource handle rather than the tag ID. Meanwhile, caching the gsource and TCPChardevTelnetInit (which holds the handshake data) in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers. Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-5-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 67 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 2475e1d52f..82c7d7a323 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -40,6 +40,11 @@ #define TCP_MAX_FDS 16 +typedef struct { + char buf[21]; + size_t buflen; +} TCPChardevTelnetInit; + typedef struct { Chardev parent; QIOChannel *ioc; /* Client I/O channel */ @@ -60,6 +65,8 @@ typedef struct { bool is_listen; bool is_telnet; bool is_tn3270; + GSource *telnet_source; + TCPChardevTelnetInit *telnet_init; GSource *reconnect_timer; int64_t reconnect_time; @@ -70,6 +77,7 @@ typedef struct { OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET) static gboolean socket_reconnect_timeout(gpointer opaque); +static void tcp_chr_telnet_init(Chardev *chr); static void tcp_chr_reconn_timer_cancel(SocketChardev *s) { @@ -556,6 +564,15 @@ static void tcp_chr_connect(void *opaque) qemu_chr_be_event(chr, CHR_EVENT_OPENED); } +static void tcp_chr_telnet_destroy(SocketChardev *s) +{ + if (s->telnet_source) { + g_source_destroy(s->telnet_source); + g_source_unref(s->telnet_source); + s->telnet_source = NULL; + } +} + static void tcp_chr_update_read_handler(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -570,6 +587,10 @@ static void tcp_chr_update_read_handler(Chardev *chr) chr, NULL, chr->gcontext); } + if (s->telnet_source) { + tcp_chr_telnet_init(CHARDEV(s)); + } + if (!s->connected) { return; } @@ -583,32 +604,30 @@ static void tcp_chr_update_read_handler(Chardev *chr) } } -typedef struct { - Chardev *chr; - char buf[21]; - size_t buflen; -} TCPChardevTelnetInit; - static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, GIOCondition cond G_GNUC_UNUSED, gpointer user_data) { - TCPChardevTelnetInit *init = user_data; + SocketChardev *s = user_data; + Chardev *chr = CHARDEV(s); + TCPChardevTelnetInit *init = s->telnet_init; ssize_t ret; + assert(init); + ret = qio_channel_write(ioc, init->buf, init->buflen, NULL); if (ret < 0) { if (ret == QIO_CHANNEL_ERR_BLOCK) { ret = 0; } else { - tcp_chr_disconnect(init->chr); + tcp_chr_disconnect(chr); goto end; } } init->buflen -= ret; if (init->buflen == 0) { - tcp_chr_connect(init->chr); + tcp_chr_connect(chr); goto end; } @@ -617,16 +636,30 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc, return G_SOURCE_CONTINUE; end: - g_free(init); + g_free(s->telnet_init); + s->telnet_init = NULL; + g_source_unref(s->telnet_source); + s->telnet_source = NULL; return G_SOURCE_REMOVE; } static void tcp_chr_telnet_init(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); - TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1); + TCPChardevTelnetInit *init; size_t n = 0; + /* Destroy existing task */ + tcp_chr_telnet_destroy(s); + + if (s->telnet_init) { + /* We are possibly during a handshake already */ + goto cont; + } + + s->telnet_init = g_new0(TCPChardevTelnetInit, 1); + init = s->telnet_init; + #define IACSET(x, a, b, c) \ do { \ x[n++] = a; \ @@ -634,7 +667,6 @@ static void tcp_chr_telnet_init(Chardev *chr) x[n++] = c; \ } while (0) - init->chr = chr; if (!s->is_tn3270) { init->buflen = 12; /* Prep the telnet negotion to put telnet in binary, @@ -657,10 +689,11 @@ static void tcp_chr_telnet_init(Chardev *chr) #undef IACSET - qio_channel_add_watch( - s->ioc, G_IO_OUT, - tcp_chr_telnet_init_io, - init, NULL); +cont: + s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT, + tcp_chr_telnet_init_io, + s, NULL, + chr->gcontext); } @@ -835,6 +868,8 @@ static void char_socket_finalize(Object *obj) tcp_chr_free_connection(chr); tcp_chr_reconn_timer_cancel(s); qapi_free_SocketAddress(s->addr); + tcp_chr_telnet_destroy(s); + g_free(s->telnet_init); if (s->listener) { qio_net_listener_set_client_func_full(s->listener, NULL, NULL, NULL, chr->gcontext); -- cgit v1.2.1 From c7278b43550f501a6d62388eb7a7e68a5b43c044 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:16 +0800 Subject: chardev: introduce chr_machine_done hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce ChardevClass.chr_machine_done() hook so that chardevs can run customized procedures after machine init. There was an existing mux user already that did similar thing but used a raw machine done notifier. Generalize it into a framework, and let the mux chardevs provide such a class-specific hook to achieve the same thing. Then we can move the mux related code to the char-mux.c file. Since at it, replace the mux_realized variable with the global machine_init_done varible. This notifier framework will be further leverged by other type of chardevs soon. Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-6-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-mux.c | 33 +++++++++++++++++++++++++++++---- chardev/char.c | 43 +++++++++++++++++-------------------------- include/chardev/char-mux.h | 2 -- include/chardev/char.h | 2 ++ tests/test-char.c | 1 - 5 files changed, 48 insertions(+), 33 deletions(-) diff --git a/chardev/char-mux.c b/chardev/char-mux.c index d48e78103a..1b925c8dec 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -27,6 +27,7 @@ #include "qemu/option.h" #include "chardev/char.h" #include "sysemu/block-backend.h" +#include "sysemu/sysemu.h" #include "chardev/char-mux.h" /* MUX driver for serial I/O splitting */ @@ -230,14 +231,12 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size) } } -bool muxes_realized; - void mux_chr_send_all_event(Chardev *chr, int event) { MuxChardev *d = MUX_CHARDEV(chr); int i; - if (!muxes_realized) { + if (!machine_init_done) { return; } @@ -327,7 +326,7 @@ static void qemu_chr_open_mux(Chardev *chr, /* only default to opened state if we've realized the initial * set of muxes */ - *be_opened = muxes_realized; + *be_opened = machine_init_done; qemu_chr_fe_init(&d->chr, drv, errp); } @@ -347,6 +346,31 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, mux->chardev = g_strdup(chardev); } +/** + * Called after processing of default and command-line-specified + * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached + * to a mux chardev. This is done here to ensure that + * output/prompts/banners are only displayed for the FE that has + * focus when initial command-line processing/machine init is + * completed. + * + * After this point, any new FE attached to any new or existing + * mux will receive CHR_EVENT_OPENED notifications for the BE + * immediately. + */ +static int open_muxes(Chardev *chr) +{ + /* send OPENED to all already-attached FEs */ + mux_chr_send_all_event(chr, CHR_EVENT_OPENED); + /* + * mark mux as OPENED so any new FEs will immediately receive + * OPENED event + */ + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + + return 0; +} + static void char_mux_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -357,6 +381,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data) cc->chr_accept_input = mux_chr_accept_input; cc->chr_add_watch = mux_chr_add_watch; cc->chr_be_event = mux_chr_be_event; + cc->chr_machine_done = open_muxes; } static const TypeInfo char_mux_type_info = { diff --git a/chardev/char.c b/chardev/char.c index 5d7b079ef0..a6250cac80 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -281,40 +281,31 @@ static const TypeInfo char_type_info = { .class_init = char_class_init, }; -/** - * Called after processing of default and command-line-specified - * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached - * to a mux chardev. This is done here to ensure that - * output/prompts/banners are only displayed for the FE that has - * focus when initial command-line processing/machine init is - * completed. - * - * After this point, any new FE attached to any new or existing - * mux will receive CHR_EVENT_OPENED notifications for the BE - * immediately. - */ -static int open_muxes(Object *child, void *opaque) +static int chardev_machine_done_notify_one(Object *child, void *opaque) { - if (CHARDEV_IS_MUX(child)) { - /* send OPENED to all already-attached FEs */ - mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED); - /* mark mux as OPENED so any new FEs will immediately receive - * OPENED event - */ - qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED); + Chardev *chr = (Chardev *)child; + ChardevClass *class = CHARDEV_GET_CLASS(chr); + + if (class->chr_machine_done) { + return class->chr_machine_done(chr); } return 0; } -static void muxes_realize_done(Notifier *notifier, void *unused) +static void chardev_machine_done_hook(Notifier *notifier, void *unused) { - muxes_realized = true; - object_child_foreach(get_chardevs_root(), open_muxes, NULL); + int ret = object_child_foreach(get_chardevs_root(), + chardev_machine_done_notify_one, NULL); + + if (ret) { + error_report("Failed to call chardev machine_done hooks"); + exit(1); + } } -static Notifier muxes_realize_notify = { - .notify = muxes_realize_done, +static Notifier chardev_machine_done_notify = { + .notify = chardev_machine_done_hook, }; static bool qemu_chr_is_busy(Chardev *s) @@ -1118,7 +1109,7 @@ static void register_types(void) * as part of realize functions like serial_isa_realizefn when -nographic * is specified */ - qemu_add_machine_init_done_notifier(&muxes_realize_notify); + qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); } type_init(register_types); diff --git a/include/chardev/char-mux.h b/include/chardev/char-mux.h index 8928977897..1e13187767 100644 --- a/include/chardev/char-mux.h +++ b/include/chardev/char-mux.h @@ -27,8 +27,6 @@ #include "chardev/char.h" #include "chardev/char-fe.h" -extern bool muxes_realized; - #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) diff --git a/include/chardev/char.h b/include/chardev/char.h index ebf1e0ba04..04de45795e 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -248,6 +248,8 @@ typedef struct ChardevClass { void (*chr_set_echo)(Chardev *chr, bool echo); void (*chr_set_fe_open)(Chardev *chr, int fe_open); void (*chr_be_event)(Chardev *s, int event); + /* Return 0 if succeeded, 1 if failed */ + int (*chr_machine_done)(Chardev *chr); } ChardevClass; Chardev *qemu_chardev_new(const char *id, const char *typename, diff --git a/tests/test-char.c b/tests/test-char.c index b3a77af085..c731313098 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -166,7 +166,6 @@ static void char_mux_test(void) FeHandler h1 = { 0, }, h2 = { 0, }; CharBackend chr_be1, chr_be2; - muxes_realized = true; /* done after machine init */ opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); -- cgit v1.2.1 From 3e7d4d20d3a528b1ed10b1dc3d83119bfb0c5f24 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:17 +0800 Subject: chardev: use chardev's gcontext for async connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generalize the function to create the async QIO task connection. Also, fix the context pointer to use the chardev's gcontext. Reviewed-by: Paolo Bonzini Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-7-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 82c7d7a323..09aa345869 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -902,11 +902,22 @@ cleanup: object_unref(OBJECT(sioc)); } +static void tcp_chr_connect_async(Chardev *chr) +{ + SocketChardev *s = SOCKET_CHARDEV(chr); + QIOChannelSocket *sioc; + + sioc = qio_channel_socket_new(); + tcp_chr_set_client_ioc_name(chr, sioc); + qio_channel_socket_connect_async(sioc, s->addr, + qemu_chr_socket_connected, + chr, NULL, chr->gcontext); +} + static gboolean socket_reconnect_timeout(gpointer opaque) { Chardev *chr = CHARDEV(opaque); SocketChardev *s = SOCKET_CHARDEV(opaque); - QIOChannelSocket *sioc; g_source_unref(s->reconnect_timer); s->reconnect_timer = NULL; @@ -915,11 +926,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque) return false; } - sioc = qio_channel_socket_new(); - tcp_chr_set_client_ioc_name(chr, sioc); - qio_channel_socket_connect_async(sioc, s->addr, - qemu_chr_socket_connected, - chr, NULL, NULL); + tcp_chr_connect_async(chr); return false; } @@ -999,11 +1006,7 @@ static void qmp_chardev_open_socket(Chardev *chr, } if (s->reconnect_time) { - sioc = qio_channel_socket_new(); - tcp_chr_set_client_ioc_name(chr, sioc); - qio_channel_socket_connect_async(sioc, s->addr, - qemu_chr_socket_connected, - chr, NULL, NULL); + tcp_chr_connect_async(chr); } else { if (s->is_listen) { char *name; -- cgit v1.2.1 From 25679e5d58e258e9950685ffbd0cae4cd40d9cc2 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:18 +0800 Subject: chardev: tcp: postpone async connection setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows the socket chardev async connection be setup with non-default gcontext. We do it by postponing the setup to machine done, since until then we can know which context we should run the async operation on. Reviewed-by: Paolo Bonzini Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-8-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 09aa345869..f6ad6ee4d8 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1005,9 +1005,8 @@ static void qmp_chardev_open_socket(Chardev *chr, s->reconnect_time = reconnect; } - if (s->reconnect_time) { - tcp_chr_connect_async(chr); - } else { + /* If reconnect_time is set, will do that in chr_machine_done. */ + if (!s->reconnect_time) { if (s->is_listen) { char *name; s->listener = qio_net_listener_new(); @@ -1139,6 +1138,17 @@ char_socket_get_connected(Object *obj, Error **errp) return s->connected; } +static int tcp_chr_machine_done_hook(Chardev *chr) +{ + SocketChardev *s = SOCKET_CHARDEV(chr); + + if (s->reconnect_time) { + tcp_chr_connect_async(chr); + } + + return 0; +} + static void char_socket_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -1154,6 +1164,7 @@ static void char_socket_class_init(ObjectClass *oc, void *data) cc->chr_add_client = tcp_chr_add_client; cc->chr_add_watch = tcp_chr_add_watch; cc->chr_update_read_handler = tcp_chr_update_read_handler; + cc->chr_machine_done = tcp_chr_machine_done_hook; object_class_property_add(oc, "addr", "SocketAddress", char_socket_get_addr, NULL, -- cgit v1.2.1 From 05b6cc4ae2efbafad9b45a93bccfcae51d018043 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 6 Mar 2018 13:33:19 +0800 Subject: chardev: tcp: let TLS run on chardev context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now qio_channel_tls_handshake() is ready to receive the context. Let socket chardev use it, then the TLS handshake of chardev will always be with the chardev's context. Signed-off-by: Peter Xu Message-Id: <20180306053320.15401-9-peterx@redhat.com> Acked-by: Stefan Hajnoczi Reviewed-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index f6ad6ee4d8..36a8fcc194 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -751,7 +751,7 @@ static void tcp_chr_tls_init(Chardev *chr) tcp_chr_tls_handshake, chr, NULL, - NULL); + chr->gcontext); } -- cgit v1.2.1 From 4397a018473ae589be959ba93cb491cbd77fe789 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 8 Mar 2018 16:17:59 +0100 Subject: scsi: support NDOB (no data-out buffer) for WRITE SAME commands A NDOB bit set to one specifies that the disk shall not transfer data from the data-out buffer and shall process the command as if the data-out buffer contained user data set to all zeroes. Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 2 +- hw/scsi/scsi-disk.c | 2 +- tests/virtio-scsi-test.c | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 1eaeffc830..9646743a7d 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -944,7 +944,7 @@ static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) break; case WRITE_SAME_10: case WRITE_SAME_16: - cmd->xfer = dev->blocksize; + cmd->xfer = buf[1] & 1 ? 0 : dev->blocksize; break; case READ_CAPACITY_10: cmd->xfer = 8; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index c65c1ce56d..5b7a48f5a5 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1807,7 +1807,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) return; } - if (buffer_is_zero(inbuf, s->qdev.blocksize)) { + if ((req->cmd.buf[1] & 0x1) || buffer_is_zero(inbuf, s->qdev.blocksize)) { int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0; /* The request is used as the AIO opaque value, so add a ref. */ diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index 7393d69bb2..037872bb98 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -216,6 +216,9 @@ static void test_unaligned_write_same(void) const uint8_t write_same_cdb_2[VIRTIO_SCSI_CDB_SIZE] = { 0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00 }; + const uint8_t write_same_cdb_ndob[VIRTIO_SCSI_CDB_SIZE] = { + 0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00 + }; vs = qvirtio_scsi_pci_init(PCI_SLOT); @@ -225,6 +228,9 @@ static void test_unaligned_write_same(void) g_assert_cmphex(0, ==, virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512, NULL)); + g_assert_cmphex(0, ==, + virtio_scsi_do_command(vs, write_same_cdb_ndob, NULL, 0, NULL, 0, NULL)); + qvirtio_scsi_pci_free(vs); } -- cgit v1.2.1 From 8cc436d9c513797291b531bbf06ef306f41e8c9b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 28 Feb 2018 10:32:23 +0100 Subject: hw/i386: make IOMMUs configurable via default-configs/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow distributions to disable the Intel and/or AMD IOMMU devices. Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- default-configs/i386-softmmu.mak | 2 ++ default-configs/x86_64-softmmu.mak | 2 ++ hw/i386/Makefile.objs | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 3326e3e0bb..9e5a29fa4a 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -63,3 +63,5 @@ CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y CONFIG_I2C=y +CONFIG_VTD=y +CONFIG_AMD_IOMMU=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 1c6cda1d9a..7baf91b921 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -63,3 +63,5 @@ CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y CONFIG_I2C=y +CONFIG_VTD=y +CONFIG_AMD_IOMMU=y diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index fd279e7584..fa87a14152 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,8 +2,8 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o -obj-y += x86-iommu.o intel_iommu.o -obj-y += amd_iommu.o +obj-$(CONFIG_VTD) += x86-iommu.o intel_iommu.o +obj-$(CONFIG_AMD_IOMMU) += x86-iommu.o amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-$(CONFIG_VMPORT) += vmport.o obj-$(CONFIG_VMMOUSE) += vmmouse.o -- cgit v1.2.1 From 7e563bfb8a5104ff0eed0fff8d13cbe63a25d17c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 Feb 2018 12:06:47 +0100 Subject: Polish the version strings containing the package version Since commit 67a1de0d195a there is no space anymore between the version number and the parentheses when running configure with --with-pkgversion=foo : $ qemu-system-s390x --version QEMU emulator version 2.11.50(foo) But the space is included when building without that option when building from a git checkout: $ qemu-system-s390x --version QEMU emulator version 2.11.50 (v2.11.0-1494-gbec9c64-dirty) The same confusion exists with the "query-version" QMP command. Let's fix this by introducing a proper QEMU_FULL_VERSION definition that includes the space and parentheses, while the QEMU_PKGVERSION should just cleanly contain the package version string itself. Note that this also changes the behavior of the "query-version" QMP command (the space and parentheses are not included there anymore), but that's supposed to be OK since the strings there are not meant to be parsed by other tools. Fixes: 67a1de0d195a6185c39b436159c9ffc7720bf979 Buglink: https://bugs.launchpad.net/qemu/+bug/1673373 Signed-off-by: Thomas Huth Message-Id: <1518692807-25859-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- Makefile | 20 +++++++++++--------- bsd-user/main.c | 2 +- configure | 2 +- linux-user/main.c | 2 +- qemu-img.c | 2 +- qemu-io.c | 2 +- qemu-nbd.c | 2 +- qga/main.c | 2 +- scsi/qemu-pr-helper.c | 2 +- ui/cocoa.m | 2 +- vl.c | 2 +- 11 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 5d9ef3b8fd..416a81c7ca 100644 --- a/Makefile +++ b/Makefile @@ -434,21 +434,23 @@ all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules qemu-version.h: FORCE $(call quiet-command, \ (cd $(SRC_PATH); \ - printf '#define QEMU_PKGVERSION '; \ if test -n "$(PKGVERSION)"; then \ - printf '"$(PKGVERSION)"\n'; \ + pkgvers="$(PKGVERSION)"; \ else \ if test -d .git; then \ - printf '" ('; \ - git describe --match 'v*' 2>/dev/null | tr -d '\n'; \ + pkgvers=$$(git describe --match 'v*' 2>/dev/null | tr -d '\n');\ if ! git diff-index --quiet HEAD &>/dev/null; then \ - printf -- '-dirty'; \ + pkgvers="$${pkgvers}-dirty"; \ fi; \ - printf ')"\n'; \ - else \ - printf '""\n'; \ fi; \ - fi) > $@.tmp) + fi; \ + printf "#define QEMU_PKGVERSION \"$${pkgvers}\"\n"; \ + if test -n "$${pkgvers}"; then \ + printf '#define QEMU_FULL_VERSION QEMU_VERSION " (" QEMU_PKGVERSION ")"\n'; \ + else \ + printf '#define QEMU_FULL_VERSION QEMU_VERSION\n'; \ + fi; \ + ) > $@.tmp) $(call quiet-command, if ! cmp -s $@ $@.tmp; then \ mv $@.tmp $@; \ else \ diff --git a/bsd-user/main.c b/bsd-user/main.c index efef5ff8c5..05aa5594a9 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -649,7 +649,7 @@ void cpu_loop(CPUSPARCState *env) static void usage(void) { - printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION + printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n" "usage: qemu-" TARGET_NAME " [options] program [arguments...]\n" "BSD CPU emulator (compiled for %s emulation)\n" diff --git a/configure b/configure index f74e1f3b7c..26d56eb5bb 100755 --- a/configure +++ b/configure @@ -1163,7 +1163,7 @@ for opt do ;; --disable-blobs) blobs="no" ;; - --with-pkgversion=*) pkgversion=" ($optarg)" + --with-pkgversion=*) pkgversion="$optarg" ;; --with-coroutine=*) coroutine="$optarg" ;; diff --git a/linux-user/main.c b/linux-user/main.c index 7bc9bc79b0..abbd14e208 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4163,7 +4163,7 @@ static void handle_arg_strace(const char *arg) static void handle_arg_version(const char *arg) { - printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION + printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n"); exit(EXIT_SUCCESS); } diff --git a/qemu-img.c b/qemu-img.c index 088d89043e..855fa52514 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -46,7 +46,7 @@ #include "crypto/init.h" #include "trace/control.h" -#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \ +#define QEMU_IMG_VERSION "qemu-img version " QEMU_FULL_VERSION \ "\n" QEMU_COPYRIGHT "\n" typedef struct img_cmd_t { diff --git a/qemu-io.c b/qemu-io.c index 160fb2a89f..e692c555e0 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -558,7 +558,7 @@ int main(int argc, char **argv) trace_file = trace_opt_parse(optarg); break; case 'V': - printf("%s version " QEMU_VERSION QEMU_PKGVERSION "\n" + printf("%s version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n", progname); exit(0); case 'h': diff --git a/qemu-nbd.c b/qemu-nbd.c index ed5d9b5062..0af0560ad1 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -130,7 +130,7 @@ QEMU_HELP_BOTTOM "\n" static void version(const char *name) { printf( -"%s " QEMU_VERSION QEMU_PKGVERSION "\n" +"%s " QEMU_FULL_VERSION "\n" "Written by Anthony Liguori.\n" "\n" QEMU_COPYRIGHT "\n" diff --git a/qga/main.c b/qga/main.c index f9c83050c5..837a75a46a 100644 --- a/qga/main.c +++ b/qga/main.c @@ -218,7 +218,7 @@ static void usage(const char *cmd) { printf( "Usage: %s [-m -p ] []\n" -"QEMU Guest Agent " QEMU_VERSION QEMU_PKGVERSION "\n" +"QEMU Guest Agent " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n" "\n" " -m, --method transport method: one of unix-listen, virtio-serial,\n" diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 9fe615c73c..3facbba170 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -102,7 +102,7 @@ QEMU_HELP_BOTTOM "\n" static void version(const char *name) { printf( -"%s " QEMU_VERSION QEMU_PKGVERSION "\n" +"%s " QEMU_FULL_VERSION "\n" "Written by Paolo Bonzini.\n" "\n" QEMU_COPYRIGHT "\n" diff --git a/ui/cocoa.m b/ui/cocoa.m index 18de0bb3ea..110b393e4e 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1330,7 +1330,7 @@ QemuCocoaView *cocoaView; /* Create the version string*/ NSString *version_string; version_string = [[NSString alloc] initWithFormat: - @"QEMU emulator version %s%s", QEMU_VERSION, QEMU_PKGVERSION]; + @"QEMU emulator version %s", QEMU_FULL_VERSION]; [version_label setStringValue: version_string]; [superView addSubview: version_label]; diff --git a/vl.c b/vl.c index 26662eb9e7..e81152417a 100644 --- a/vl.c +++ b/vl.c @@ -1948,7 +1948,7 @@ static void main_loop(void) static void version(void) { - printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION "\n" + printf("QEMU emulator version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n"); } -- cgit v1.2.1 From 148b2ba1145af29a7afac349b8169790e06d6df4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 7 Mar 2018 10:24:04 +0100 Subject: hw/mips/jazz: Fix implicit creation of "-drive if=scsi" devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The global hack for creating SCSI devices has recently been removed, but this apparently broke SCSI devices on some boards that were not ready for this change yet. For the pica61 machine you now get: $ mips64-softmmu/qemu-system-mips64 -M pica61 -cdrom x.iso qemu-system-mips64: -cdrom x.iso: machine type does not support if=scsi,bus=0,unit=2 Fix it by calling scsi_bus_legacy_handle_cmdline() after creating the corresponding SCSI controller. Fixes: 1454509726719e0933c800fad00d6999752688ea Signed-off-by: Thomas Huth Message-Id: <1520414644-11535-1-git-send-email-thuth@redhat.com> Reviewed-by: Hervé Poussineau Signed-off-by: Paolo Bonzini --- hw/mips/mips_jazz.c | 7 ++++--- hw/scsi/esp.c | 12 +++++++----- include/hw/scsi/esp.h | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 08e6f620fc..e135385265 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -146,6 +146,7 @@ static void mips_jazz_init(MachineState *machine, MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); MemoryRegion *bios2 = g_new(MemoryRegion, 1); + ESPState *esp; /* init CPUs */ cpu = MIPS_CPU(cpu_create(machine->cpu_type)); @@ -277,9 +278,9 @@ static void mips_jazz_init(MachineState *machine, } /* SCSI adapter */ - esp_init(0x80002000, 0, - rc4030_dma_read, rc4030_dma_write, dmas[0], - qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); + esp = esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0], + qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); + scsi_bus_legacy_handle_cmdline(&esp->bus); /* Floppy */ for (n = 0; n < MAX_FD; n++) { diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 45975c21e8..64ec285826 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -618,11 +618,11 @@ static const MemoryRegionOps sysbus_esp_mem_ops = { .valid.accepts = esp_mem_accepts, }; -void esp_init(hwaddr espaddr, int it_shift, - ESPDMAMemoryReadWriteFunc dma_memory_read, - ESPDMAMemoryReadWriteFunc dma_memory_write, - void *dma_opaque, qemu_irq irq, qemu_irq *reset, - qemu_irq *dma_enable) +ESPState *esp_init(hwaddr espaddr, int it_shift, + ESPDMAMemoryReadWriteFunc dma_memory_read, + ESPDMAMemoryReadWriteFunc dma_memory_write, + void *dma_opaque, qemu_irq irq, qemu_irq *reset, + qemu_irq *dma_enable) { DeviceState *dev; SysBusDevice *s; @@ -644,6 +644,8 @@ void esp_init(hwaddr espaddr, int it_shift, sysbus_mmio_map(s, 0, espaddr); *reset = qdev_get_gpio_in(dev, 0); *dma_enable = qdev_get_gpio_in(dev, 1); + + return esp; } static const struct SCSIBusInfo esp_scsi_info = { diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index 3b160f858c..93fdaced67 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -7,11 +7,6 @@ /* esp.c */ #define ESP_MAX_DEVS 7 typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len); -void esp_init(hwaddr espaddr, int it_shift, - ESPDMAMemoryReadWriteFunc dma_memory_read, - ESPDMAMemoryReadWriteFunc dma_memory_write, - void *dma_opaque, qemu_irq irq, qemu_irq *reset, - qemu_irq *dma_enable); #define ESP_REGS 16 #define TI_BUFSZ 16 @@ -136,6 +131,11 @@ typedef struct { #define TCHI_FAS100A 0x4 #define TCHI_AM53C974 0x12 +ESPState *esp_init(hwaddr espaddr, int it_shift, + ESPDMAMemoryReadWriteFunc dma_memory_read, + ESPDMAMemoryReadWriteFunc dma_memory_write, + void *dma_opaque, qemu_irq irq, qemu_irq *reset, + qemu_irq *dma_enable); void esp_dma_enable(ESPState *s, int irq, int level); void esp_request_cancelled(SCSIRequest *req); void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid); -- cgit v1.2.1 From b9b758175424857a900c3253ffb8e55fa0a3fdd6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 9 Mar 2018 12:12:29 +0100 Subject: rcutorture: remove synchronize_rcu from readers This gives much worse numbers for readers, especially if synchronize_rcu is made more expensive as is the case with --enable-membarrier. Before: $ tests/rcutorture 10 stress 10 n_reads: 98304 n_updates: 529 n_mberror: 0 rcu_stress_count: 98302 2 0 0 0 0 0 0 0 0 0 After: $ tests/rcutorture 10 stress 10 n_reads: 165158482 n_updates: 429 n_mberror: 0 rcu_stress_count: 165154364 4118 0 0 0 0 0 0 0 0 0 Signed-off-by: Paolo Bonzini --- tests/rcutorture.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/rcutorture.c b/tests/rcutorture.c index 4002ecf123..49311c82ea 100644 --- a/tests/rcutorture.c +++ b/tests/rcutorture.c @@ -238,7 +238,6 @@ long long rcu_stress_count[RCU_STRESS_PIPE_LEN + 1]; static void *rcu_read_stress_test(void *arg) { int i; - int itercnt = 0; struct rcu_stress *p; int pc; long long n_reads_local = 0; @@ -269,9 +268,6 @@ static void *rcu_read_stress_test(void *arg) } rcu_stress_local[pc]++; n_reads_local++; - if ((++itercnt % 0x1000) == 0) { - synchronize_rcu(); - } } qemu_mutex_lock(&counts_mutex); n_reads += n_reads_local; -- cgit v1.2.1 From 729c0ddd3cdf16973d850b1ee7c5234a1e4dddbb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 23 Feb 2018 13:58:31 +0100 Subject: docs: document atomic_load_acquire and atomic_store_release We will use them in the next patch, document what they do. Signed-off-by: Paolo Bonzini --- docs/devel/atomics.txt | 57 ++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/docs/devel/atomics.txt b/docs/devel/atomics.txt index 10c5fa37e8..a4db3a4aaa 100644 --- a/docs/devel/atomics.txt +++ b/docs/devel/atomics.txt @@ -122,20 +122,30 @@ In general, if the algorithm you are writing includes both writes and reads on the same side, it is generally simpler to use sequentially consistent primitives. -When using this model, variables are accessed with atomic_read() and -atomic_set(), and restrictions to the ordering of accesses is enforced +When using this model, variables are accessed with: + +- atomic_read() and atomic_set(); these prevent the compiler from + optimizing accesses out of existence and creating unsolicited + accesses, but do not otherwise impose any ordering on loads and + stores: both the compiler and the processor are free to reorder + them. + +- atomic_load_acquire(), which guarantees the LOAD to appear to + happen, with respect to the other components of the system, + before all the LOAD or STORE operations specified afterwards. + Operations coming before atomic_load_acquire() can still be + reordered after it. + +- atomic_store_release(), which guarantees the STORE to appear to + happen, with respect to the other components of the system, + after all the LOAD or STORE operations specified afterwards. + Operations coming after atomic_store_release() can still be + reordered after it. + +Restrictions to the ordering of accesses can also be specified using the memory barrier macros: smp_rmb(), smp_wmb(), smp_mb(), smp_mb_acquire(), smp_mb_release(), smp_read_barrier_depends(). -atomic_read() and atomic_set() prevents the compiler from using -optimizations that might otherwise optimize accesses out of existence -on the one hand, or that might create unsolicited accesses on the other. -In general this should not have any effect, because the same compiler -barriers are already implied by memory barriers. However, it is useful -to do so, because it tells readers which variables are shared with -other threads, and which are local to the current thread or protected -by other, more mundane means. - Memory barriers control the order of references to shared memory. They come in six kinds: @@ -232,7 +242,7 @@ make atomic_mb_set() the more expensive operation. There are two common cases in which atomic_mb_read and atomic_mb_set generate too many memory barriers, and thus it can be useful to manually -place barriers instead: +place barriers, or use atomic_load_acquire/atomic_store_release instead: - when a data structure has one thread that is always a writer and one thread that is always a reader, manual placement of @@ -243,18 +253,15 @@ place barriers instead: thread 1 thread 1 ------------------------- ------------------------ (other writes) - smp_mb_release() - atomic_mb_set(&a, x) atomic_set(&a, x) - smp_wmb() - atomic_mb_set(&b, y) atomic_set(&b, y) + atomic_mb_set(&a, x) atomic_store_release(&a, x) + atomic_mb_set(&b, y) atomic_store_release(&b, y) => thread 2 thread 2 ------------------------- ------------------------ - y = atomic_mb_read(&b) y = atomic_read(&b) - smp_rmb() - x = atomic_mb_read(&a) x = atomic_read(&a) - smp_mb_acquire() + y = atomic_mb_read(&b) y = atomic_load_acquire(&b) + x = atomic_mb_read(&a) x = atomic_load_acquire(&a) + (other reads) Note that the barrier between the stores in thread 1, and between the loads in thread 2, has been optimized here to a write or a @@ -276,7 +283,6 @@ place barriers instead: smp_mb_acquire(); Similarly, atomic_mb_set() can be transformed as follows: - smp_mb(): smp_mb_release(); for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++) @@ -284,6 +290,8 @@ place barriers instead: smp_mb(); + The other thread can still use atomic_mb_read()/atomic_mb_set(). + The two tricks can be combined. In this case, splitting a loop in two lets you hoist the barriers out of the loops _and_ eliminate the expensive smp_mb(): @@ -296,8 +304,6 @@ expensive smp_mb(): atomic_set(&a[i], false); smp_mb(); - The other thread can still use atomic_mb_read()/atomic_mb_set() - Memory barrier pairing ---------------------- @@ -386,10 +392,7 @@ and memory barriers, and the equivalents in QEMU: note that smp_store_mb() is a little weaker than atomic_mb_set(). atomic_mb_read() compiles to the same instructions as Linux's smp_load_acquire(), but this should be treated as an implementation - detail. QEMU does have atomic_load_acquire() and atomic_store_release() - macros, but for now they are only used within atomic.h. This may - change in the future. - + detail. SOURCES ======= -- cgit v1.2.1 From 77a8b8462b02a10aea5cad389a8f9260f79ede36 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Feb 2018 09:23:31 +0100 Subject: rcu: make memory barriers more explicit Prepare for introducing smp_mb_placeholder() and smp_mb_global(). The new smp_mb() in synchronize_rcu() is not strictly necessary, since the first atomic_mb_set for rcu_gp_ctr provides the required ordering. However, synchronize_rcu is not performance critical, and it *will* be necessary to introduce a smp_mb_global before calling wait_for_readers(). Signed-off-by: Paolo Bonzini --- include/qemu/rcu.h | 15 +++++++++++++-- util/rcu.c | 12 +++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index f19413d649..625f09ac09 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -79,7 +79,10 @@ static inline void rcu_read_lock(void) } ctr = atomic_read(&rcu_gp_ctr); - atomic_xchg(&p_rcu_reader->ctr, ctr); + atomic_set(&p_rcu_reader->ctr, ctr); + + /* Write p_rcu_reader->ctr before reading RCU-protected pointers. */ + smp_mb(); } static inline void rcu_read_unlock(void) @@ -91,7 +94,15 @@ static inline void rcu_read_unlock(void) return; } - atomic_xchg(&p_rcu_reader->ctr, 0); + /* Ensure that the critical section is seen to precede the + * store to p_rcu_reader->ctr. Together with the following + * smp_mb(), this ensures writes to p_rcu_reader->ctr + * are sequentially consistent. + */ + atomic_store_release(&p_rcu_reader->ctr, 0); + + /* Write p_rcu_reader->ctr before reading p_rcu_reader->waiting. */ + smp_mb(); if (unlikely(atomic_read(&p_rcu_reader->waiting))) { atomic_set(&p_rcu_reader->waiting, false); qemu_event_set(&rcu_gp_event); diff --git a/util/rcu.c b/util/rcu.c index f4d09c8304..7366dc50dd 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -92,8 +92,9 @@ static void wait_for_readers(void) atomic_set(&index->waiting, true); } - /* Here, order the stores to index->waiting before the - * loads of index->ctr. + /* Here, order the stores to index->waiting before the loads of + * index->ctr. Pairs with smp_mb() in rcu_read_unlock(), + * ensuring that the loads of index->ctr are sequentially consistent. */ smp_mb(); @@ -142,8 +143,13 @@ static void wait_for_readers(void) void synchronize_rcu(void) { qemu_mutex_lock(&rcu_sync_lock); - qemu_mutex_lock(&rcu_registry_lock); + /* Write RCU-protected pointers before reading p_rcu_reader->ctr. + * Pairs with smp_mb() in rcu_read_lock(). + */ + smp_mb(); + + qemu_mutex_lock(&rcu_registry_lock); if (!QLIST_EMPTY(®istry)) { /* In either case, the atomic_mb_set below blocks stores that free * old RCU-protected pointers. -- cgit v1.2.1 From c8d3877e48c4f57381d72eaf8d016bff12ce2d7c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Feb 2018 10:04:18 +0100 Subject: membarrier: introduce qemu/sys_membarrier.h This new header file provides heavy-weight "global" memory barriers that enforce memory ordering on each running thread belonging to the current process. For now, use a dummy implementation that issues memory barriers on both sides (matching what QEMU has been doing so far). Signed-off-by: Paolo Bonzini --- include/qemu/rcu.h | 7 ++++--- include/qemu/sys_membarrier.h | 17 +++++++++++++++++ util/rcu.c | 9 +++++---- 3 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 include/qemu/sys_membarrier.h diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index 625f09ac09..22876d1428 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -27,6 +27,7 @@ #include "qemu/thread.h" #include "qemu/queue.h" #include "qemu/atomic.h" +#include "qemu/sys_membarrier.h" #ifdef __cplusplus extern "C" { @@ -82,7 +83,7 @@ static inline void rcu_read_lock(void) atomic_set(&p_rcu_reader->ctr, ctr); /* Write p_rcu_reader->ctr before reading RCU-protected pointers. */ - smp_mb(); + smp_mb_placeholder(); } static inline void rcu_read_unlock(void) @@ -96,13 +97,13 @@ static inline void rcu_read_unlock(void) /* Ensure that the critical section is seen to precede the * store to p_rcu_reader->ctr. Together with the following - * smp_mb(), this ensures writes to p_rcu_reader->ctr + * smp_mb_placeholder(), this ensures writes to p_rcu_reader->ctr * are sequentially consistent. */ atomic_store_release(&p_rcu_reader->ctr, 0); /* Write p_rcu_reader->ctr before reading p_rcu_reader->waiting. */ - smp_mb(); + smp_mb_placeholder(); if (unlikely(atomic_read(&p_rcu_reader->waiting))) { atomic_set(&p_rcu_reader->waiting, false); qemu_event_set(&rcu_gp_event); diff --git a/include/qemu/sys_membarrier.h b/include/qemu/sys_membarrier.h new file mode 100644 index 0000000000..9ce7f5210b --- /dev/null +++ b/include/qemu/sys_membarrier.h @@ -0,0 +1,17 @@ +/* + * Process-global memory barriers + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Author: Paolo Bonzini + */ + +#ifndef QEMU_SYS_MEMBARRIER_H +#define QEMU_SYS_MEMBARRIER_H 1 + +/* Keep it simple, execute a real memory barrier on both sides. */ +static inline void smp_mb_global_init(void) {} +#define smp_mb_global() smp_mb() +#define smp_mb_placeholder() smp_mb() + +#endif diff --git a/util/rcu.c b/util/rcu.c index 7366dc50dd..5676c22bd1 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -93,10 +93,10 @@ static void wait_for_readers(void) } /* Here, order the stores to index->waiting before the loads of - * index->ctr. Pairs with smp_mb() in rcu_read_unlock(), + * index->ctr. Pairs with smp_mb_placeholder() in rcu_read_unlock(), * ensuring that the loads of index->ctr are sequentially consistent. */ - smp_mb(); + smp_mb_global(); QLIST_FOREACH_SAFE(index, ®istry, node, tmp) { if (!rcu_gp_ongoing(&index->ctr)) { @@ -145,9 +145,9 @@ void synchronize_rcu(void) qemu_mutex_lock(&rcu_sync_lock); /* Write RCU-protected pointers before reading p_rcu_reader->ctr. - * Pairs with smp_mb() in rcu_read_lock(). + * Pairs with smp_mb_placeholder() in rcu_read_lock(). */ - smp_mb(); + smp_mb_global(); qemu_mutex_lock(&rcu_registry_lock); if (!QLIST_EMPTY(®istry)) { @@ -376,6 +376,7 @@ static void rcu_init_child(void) static void __attribute__((__constructor__)) rcu_init(void) { + smp_mb_global_init(); #ifdef CONFIG_POSIX pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_child); #endif -- cgit v1.2.1 From a40161cbe9ccbcbab798c3e4d257c4bba99d153a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Feb 2018 10:05:23 +0100 Subject: membarrier: add --enable-membarrier Actually enable the global memory barriers if supported by the OS. Because only recent versions of Linux include the support, they are disabled by default. Note that it also has to be disabled for QEMU to run under Wine. Before this patch, rcutorture reports 85 ns/read for my machine, after the patch it reports 12.5 ns/read. On the other hand updates go from 50 *micro*seconds to 20 *milli*seconds. Signed-off-by: Paolo Bonzini --- configure | 42 +++++++++++++++++++++++++++++++++++- include/qemu/sys_membarrier.h | 10 +++++++++ util/Makefile.objs | 1 + util/sys_membarrier.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 util/sys_membarrier.c diff --git a/configure b/configure index 26d56eb5bb..db87fc4fed 100755 --- a/configure +++ b/configure @@ -342,7 +342,7 @@ attr="" libattr="" xfs="" tcg="yes" - +membarrier="" vhost_net="no" vhost_crypto="no" vhost_scsi="no" @@ -1161,6 +1161,10 @@ for opt do ;; --enable-attr) attr="yes" ;; + --disable-membarrier) membarrier="no" + ;; + --enable-membarrier) membarrier="yes" + ;; --disable-blobs) blobs="no" ;; --with-pkgversion=*) pkgversion="$optarg" @@ -1577,6 +1581,7 @@ disabled with --disable-FEATURE, default is enabled if available: xen-pci-passthrough brlapi BrlAPI (Braile) curl curl connectivity + membarrier membarrier system call (for Linux 4.14+ or Windows) fdt fdt device tree bluez bluez stack connectivity kvm KVM acceleration support @@ -5137,6 +5142,37 @@ if compile_prog "" "" ; then have_fsxattr=yes fi +########################################## +# check for usable membarrier system call +if test "$membarrier" = "yes"; then + have_membarrier=no + if test "$mingw32" = "yes" ; then + have_membarrier=yes + elif test "$linux" = "yes" ; then + cat > $TMPC << EOF + #include + #include + #include + #include + int main(void) { + syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0); + syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0); + exit(0); + } +EOF + if compile_prog "" "" ; then + have_membarrier=yes + fi + fi + if test "$have_membarrier" = "no"; then + feature_not_found "membarrier" "membarrier system call not available" + fi +else + # Do not enable it by default even for Mingw32, because it doesn't + # work on Wine. + membarrier=no +fi + ########################################## # check if rtnetlink.h exists and is useful have_rtnetlink=no @@ -5763,6 +5799,7 @@ fi echo "malloc trim support $malloc_trim" echo "RDMA support $rdma" echo "fdt support $fdt" +echo "membarrier $membarrier" echo "preadv support $preadv" echo "fdatasync $fdatasync" echo "madvise $madvise" @@ -6245,6 +6282,9 @@ fi if test "$fdt" = "yes" ; then echo "CONFIG_FDT=y" >> $config_host_mak fi +if test "$membarrier" = "yes" ; then + echo "CONFIG_MEMBARRIER=y" >> $config_host_mak +fi if test "$signalfd" = "yes" ; then echo "CONFIG_SIGNALFD=y" >> $config_host_mak fi diff --git a/include/qemu/sys_membarrier.h b/include/qemu/sys_membarrier.h index 9ce7f5210b..316e3dc4a2 100644 --- a/include/qemu/sys_membarrier.h +++ b/include/qemu/sys_membarrier.h @@ -9,9 +9,19 @@ #ifndef QEMU_SYS_MEMBARRIER_H #define QEMU_SYS_MEMBARRIER_H 1 +#ifdef CONFIG_MEMBARRIER +/* Only block reordering at the compiler level in the performance-critical + * side. The slow side forces processor-level ordering on all other cores + * through a system call. + */ +extern void smp_mb_global_init(void); +extern void smp_mb_global(void); +#define smp_mb_placeholder() barrier() +#else /* Keep it simple, execute a real memory barrier on both sides. */ static inline void smp_mb_global_init(void) {} #define smp_mb_global() smp_mb() #define smp_mb_placeholder() smp_mb() +#endif #endif diff --git a/util/Makefile.objs b/util/Makefile.objs index ae90b9963d..728c3541db 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -33,6 +33,7 @@ util-obj-y += throttle.o util-obj-y += getauxval.o util-obj-y += readline.o util-obj-y += rcu.o +util-obj-$(CONFIG_MEMBARRIER) += sys_membarrier.o util-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o util-obj-y += qemu-coroutine-sleep.o util-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o diff --git a/util/sys_membarrier.c b/util/sys_membarrier.c new file mode 100644 index 0000000000..8dcb53e63e --- /dev/null +++ b/util/sys_membarrier.c @@ -0,0 +1,50 @@ +/* + * Process-global memory barriers + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Author: Paolo Bonzini + */ + +#include +#include +#include + +#ifdef CONFIG_LINUX +#include +#include + +static int +membarrier(int cmd, int flags) +{ + return syscall(__NR_membarrier, cmd, flags); +} +#endif + +void smp_mb_global(void) +{ +#if defined CONFIG_WIN32 + FlushProcessWriteBuffers(); +#elif defined CONFIG_LINUX + membarrier(MEMBARRIER_CMD_SHARED, 0); +#else +#error --enable-membarrier is not supported on this operating system. +#endif +} + +void smp_mb_global_init(void) +{ +#ifdef CONFIG_LINUX + int ret = membarrier(MEMBARRIER_CMD_QUERY, 0); + if (ret < 0) { + error_report("This QEMU binary requires the membarrier system call."); + error_report("Please upgrade your system to a newer version of Linux"); + exit(1); + } + if (!(ret & MEMBARRIER_CMD_SHARED)) { + error_report("This QEMU binary requires MEMBARRIER_CMD_SHARED support."); + error_report("Please upgrade your system to a newer version of Linux"); + exit(1); + } +#endif +} -- cgit v1.2.1 From bb3d5ea858e7f888563a56c8e2d99df47882a4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:22 +0100 Subject: hw/isa: Move parallel_hds_isa_init() to hw/char/parallel-isa.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again... (after 07dc788054d7 and 9157eee1b1c0). We now extract the ISA bus specific helpers. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-2-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- MAINTAINERS | 3 ++- hw/char/Makefile.objs | 1 + hw/char/parallel-isa.c | 36 ++++++++++++++++++++++++++++++++++++ hw/char/parallel.c | 2 +- hw/i386/pc.c | 1 + hw/isa/isa-bus.c | 26 -------------------------- hw/mips/mips_fulong2e.c | 1 + hw/mips/mips_jazz.c | 1 + hw/mips/mips_malta.c | 1 + hw/sparc64/sun4u.c | 1 + include/hw/char/parallel.h | 14 ++++++++++++++ include/hw/i386/pc.h | 8 -------- 12 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 hw/char/parallel-isa.c create mode 100644 include/hw/char/parallel.h diff --git a/MAINTAINERS b/MAINTAINERS index 354a18ce49..02ac81432f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -924,7 +924,7 @@ M: Michael S. Tsirkin M: Paolo Bonzini S: Supported F: hw/char/debugcon.c -F: hw/char/parallel.c +F: hw/char/parallel* F: hw/char/serial* F: hw/dma/i8257* F: hw/i2c/pm_smbus.c @@ -939,6 +939,7 @@ F: hw/timer/i8254* F: hw/timer/mc146818rtc* F: hw/watchdog/wdt_ib700.c F: include/hw/display/vga.h +F: include/hw/char/parallel.h F: include/hw/i2c/pm_smbus.h F: include/hw/isa/i8257.h F: include/hw/timer/hpet.h diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 1bcd37e98d..1b979100b7 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -1,6 +1,7 @@ common-obj-$(CONFIG_IPACK) += ipoctal232.o common-obj-$(CONFIG_ESCC) += escc.o common-obj-$(CONFIG_PARALLEL) += parallel.o +common-obj-$(CONFIG_PARALLEL) += parallel-isa.o common-obj-$(CONFIG_PL011) += pl011.o common-obj-$(CONFIG_SERIAL) += serial.o common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o diff --git a/hw/char/parallel-isa.c b/hw/char/parallel-isa.c new file mode 100644 index 0000000000..639e179585 --- /dev/null +++ b/hw/char/parallel-isa.c @@ -0,0 +1,36 @@ +/* + * QEMU Parallel PORT (ISA bus helpers) + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: MIT + */ +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "hw/isa/isa.h" +#include "hw/char/parallel.h" + +static void parallel_init(ISABus *bus, int index, Chardev *chr) +{ + DeviceState *dev; + ISADevice *isadev; + + isadev = isa_create(bus, "isa-parallel"); + dev = DEVICE(isadev); + qdev_prop_set_uint32(dev, "index", index); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); +} + +void parallel_hds_isa_init(ISABus *bus, int n) +{ + int i; + + assert(n <= MAX_PARALLEL_PORTS); + + for (i = 0; i < n; i++) { + if (parallel_hds[i]) { + parallel_init(bus, i, parallel_hds[i]); + } + } +} diff --git a/hw/char/parallel.c b/hw/char/parallel.c index f79dc76543..1542d62201 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -28,7 +28,7 @@ #include "chardev/char-parallel.h" #include "chardev/char-fe.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" +#include "hw/char/parallel.h" #include "sysemu/sysemu.h" //#define DEBUG_PARALLEL diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0c140f4dc7..8fa51d8eba 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -26,6 +26,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/i386/apic.h" #include "hw/i386/topology.h" #include "sysemu/cpus.h" diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 0f2e426d02..63fa77effc 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/i386/pc.h" static ISABus *isabus; @@ -288,28 +287,3 @@ MemoryRegion *isa_address_space_io(ISADevice *dev) } type_init(isabus_register_types) - -static void parallel_init(ISABus *bus, int index, Chardev *chr) -{ - DeviceState *dev; - ISADevice *isadev; - - isadev = isa_create(bus, "isa-parallel"); - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "index", index); - qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); -} - -void parallel_hds_isa_init(ISABus *bus, int n) -{ - int i; - - assert(n <= MAX_PARALLEL_PORTS); - - for (i = 0; i < n; i++) { - if (parallel_hds[i]) { - parallel_init(bus, i, parallel_hds[i]); - } - } -} diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index be4f83973d..a8e8c23733 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -23,6 +23,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/block/fdc.h" #include "net/net.h" #include "hw/boards.h" diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index e135385265..c87a122ddf 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -28,6 +28,7 @@ #include "hw/mips/cpudevs.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/isa/isa.h" #include "hw/block/fdc.h" #include "sysemu/sysemu.h" diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 6f0deb99e7..c74882c7e9 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -28,6 +28,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/block/fdc.h" #include "net/net.h" #include "hw/boards.h" diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index da28ab9413..ceb1ba7eaf 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -34,6 +34,7 @@ #include "hw/pci-host/sabre.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" +#include "hw/char/parallel.h" #include "hw/timer/m48t59.h" #include "hw/block/fdc.h" #include "net/net.h" diff --git a/include/hw/char/parallel.h b/include/hw/char/parallel.h new file mode 100644 index 0000000000..d6dd62fb9f --- /dev/null +++ b/include/hw/char/parallel.h @@ -0,0 +1,14 @@ +#ifndef HW_PARALLEL_H +#define HW_PARALLEL_H + +#include "exec/memory.h" +#include "hw/isa/isa.h" +#include "chardev/char.h" + +void parallel_hds_isa_init(ISABus *bus, int n); + +bool parallel_mm_init(MemoryRegion *address_space, + hwaddr base, int it_shift, qemu_irq irq, + Chardev *chr); + +#endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index e81654eb7f..962ee7de0c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -152,14 +152,6 @@ struct PCMachineClass { #define PC_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE) -/* parallel.c */ - -void parallel_hds_isa_init(ISABus *bus, int n); - -bool parallel_mm_init(MemoryRegion *address_space, - hwaddr base, int it_shift, qemu_irq irq, - Chardev *chr); - /* i8259.c */ extern DeviceState *isa_pic; -- cgit v1.2.1 From 55f613ac25420384b2c4645420fea2f9bab15379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:23 +0100 Subject: hw/dma/i8257: Rename DMA_init() to i8257_dma_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move the header from hw/isa/ to hw/dma/ - Remove the old i386/pc dependency - use a bool type for the high_page_enable argument Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-3-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 +- hw/dma/i82374.c | 3 ++- hw/dma/i8257.c | 4 ++-- hw/i386/pc.c | 3 ++- hw/mips/mips_fulong2e.c | 3 ++- hw/mips/mips_jazz.c | 3 ++- hw/mips/mips_malta.c | 3 ++- hw/sparc/sun4m.c | 4 ---- hw/sparc64/sun4u.c | 4 ---- include/hw/dma/i8257.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/isa/i8257.h | 43 ------------------------------------------- include/hw/isa/isa.h | 2 -- 12 files changed, 62 insertions(+), 61 deletions(-) create mode 100644 include/hw/dma/i8257.h delete mode 100644 include/hw/isa/i8257.h diff --git a/MAINTAINERS b/MAINTAINERS index 02ac81432f..319ac9f929 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -940,8 +940,8 @@ F: hw/timer/mc146818rtc* F: hw/watchdog/wdt_ib700.c F: include/hw/display/vga.h F: include/hw/char/parallel.h +F: include/hw/dma/i8257.h F: include/hw/i2c/pm_smbus.h -F: include/hw/isa/i8257.h F: include/hw/timer/hpet.h F: include/hw/timer/i8254* F: include/hw/timer/mc146818rtc* diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c index 6c0f975df0..83c87d92e0 100644 --- a/hw/dma/i82374.c +++ b/hw/dma/i82374.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" +#include "hw/dma/i8257.h" #define TYPE_I82374 "i82374" #define I82374(obj) OBJECT_CHECK(I82374State, (obj), TYPE_I82374) @@ -123,7 +124,7 @@ static void i82374_realize(DeviceState *dev, Error **errp) portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), s->iobase); - DMA_init(isa_bus_from_device(ISA_DEVICE(dev)), 1); + i8257_dma_init(isa_bus_from_device(ISA_DEVICE(dev)), true); memset(s->commands, 0, sizeof(s->commands)); } diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index bd23e893bf..52675e97c9 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/isa/isa.h" -#include "hw/isa/i8257.h" +#include "hw/dma/i8257.h" #include "qemu/main-loop.h" #include "trace.h" @@ -622,7 +622,7 @@ static void i8257_register_types(void) type_init(i8257_register_types) -void DMA_init(ISABus *bus, int high_page_enable) +void i8257_dma_init(ISABus *bus, bool high_page_enable) { ISADevice *isa1, *isa2; DeviceState *d; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 8fa51d8eba..a6ceea9c64 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -41,6 +41,7 @@ #include "elf.h" #include "multiboot.h" #include "hw/timer/mc146818rtc.h" +#include "hw/dma/i8257.h" #include "hw/timer/i8254.h" #include "hw/audio/pcspk.h" #include "hw/pci/msi.h" @@ -1607,7 +1608,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, port92_init(port92, a20_line[1]); g_free(a20_line); - DMA_init(isa_bus, 0); + i8257_dma_init(isa_bus, 0); for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index a8e8c23733..1e43768589 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "hw/hw.h" #include "hw/i386/pc.h" +#include "hw/dma/i8257.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/block/fdc.h" @@ -359,7 +360,7 @@ static void mips_fulong2e_init(MachineState *machine) /* init other devices */ pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - DMA_init(isa_bus, 0); + i8257_dma_init(isa_bus, 0); /* Super I/O */ isa_create_simple(isa_bus, "i8042"); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index c87a122ddf..8b6f03a889 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -27,6 +27,7 @@ #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" #include "hw/i386/pc.h" +#include "hw/dma/i8257.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/isa/isa.h" @@ -220,7 +221,7 @@ static void mips_jazz_init(MachineState *machine, /* ISA devices */ i8259 = i8259_init(isa_bus, env->irq[4]); isa_bus_irqs(isa_bus, i8259); - DMA_init(isa_bus, 0); + i8257_dma_init(isa_bus, 0); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); pcspk_init(isa_bus, pit); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index c74882c7e9..9cb86c432e 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "hw/hw.h" #include "hw/i386/pc.h" +#include "hw/dma/i8257.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/block/fdc.h" @@ -1209,7 +1210,7 @@ void mips_malta_init(MachineState *machine) smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); g_free(smbus_eeprom_buf); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - DMA_init(isa_bus, 0); + i8257_dma_init(isa_bus, 0); /* Super I/O */ isa_create_simple(isa_bus, "i8042"); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 2b8af2c884..6471aca25d 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -98,10 +98,6 @@ struct sun4m_hwdef { uint8_t nvram_machine_id; }; -void DMA_init(ISABus *bus, int high_page_enable) -{ -} - static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index ceb1ba7eaf..0ca0243821 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -90,10 +90,6 @@ typedef struct EbusState { #define TYPE_EBUS "ebus" #define EBUS(obj) OBJECT_CHECK(EbusState, (obj), TYPE_EBUS) -void DMA_init(ISABus *bus, int high_page_enable) -{ -} - static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) { diff --git a/include/hw/dma/i8257.h b/include/hw/dma/i8257.h new file mode 100644 index 0000000000..2cab50bb6c --- /dev/null +++ b/include/hw/dma/i8257.h @@ -0,0 +1,49 @@ +#ifndef HW_I8257_H +#define HW_I8257_H + +#include "hw/hw.h" +#include "hw/isa/isa.h" +#include "exec/ioport.h" + +#define TYPE_I8257 "i8257" + +typedef struct I8257Regs { + int now[2]; + uint16_t base[2]; + uint8_t mode; + uint8_t page; + uint8_t pageh; + uint8_t dack; + uint8_t eop; + IsaDmaTransferHandler transfer_handler; + void *opaque; +} I8257Regs; + +typedef struct I8257State { + /* */ + ISADevice parent_obj; + + /* */ + int32_t base; + int32_t page_base; + int32_t pageh_base; + int32_t dshift; + + uint8_t status; + uint8_t command; + uint8_t mask; + uint8_t flip_flop; + I8257Regs regs[4]; + MemoryRegion channel_io; + MemoryRegion cont_io; + + QEMUBH *dma_bh; + bool dma_bh_scheduled; + int running; + PortioList portio_page; + PortioList portio_pageh; +} I8257State; + +void i8257_dma_init(ISABus *bus, bool high_page_enable); + +#endif diff --git a/include/hw/isa/i8257.h b/include/hw/isa/i8257.h deleted file mode 100644 index 88a2766a3f..0000000000 --- a/include/hw/isa/i8257.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef HW_I8257_H -#define HW_I8257_H - -#define TYPE_I8257 "i8257" - -typedef struct I8257Regs { - int now[2]; - uint16_t base[2]; - uint8_t mode; - uint8_t page; - uint8_t pageh; - uint8_t dack; - uint8_t eop; - IsaDmaTransferHandler transfer_handler; - void *opaque; -} I8257Regs; - -typedef struct I8257State { - /* */ - ISADevice parent_obj; - - /* */ - int32_t base; - int32_t page_base; - int32_t pageh_base; - int32_t dshift; - - uint8_t status; - uint8_t command; - uint8_t mask; - uint8_t flip_flop; - I8257Regs regs[4]; - MemoryRegion channel_io; - MemoryRegion cont_io; - - QEMUBH *dma_bh; - bool dma_bh_scheduled; - int running; - PortioList portio_page; - PortioList portio_pageh; -} I8257State; - -#endif diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 95593408ef..b9dbab24b4 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -151,6 +151,4 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) return ISA_BUS(qdev_get_parent_bus(DEVICE(d))); } -/* i8257.c */ -void DMA_init(ISABus *bus, int high_page_enable); #endif -- cgit v1.2.1 From 47973a2dbfad7fd584f37ca57d79097c9f220e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:24 +0100 Subject: hw/input/i8042: Extract declarations from i386/pc.h into input/i8042.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: David Gibson (hw/ppc) Message-Id: <20180308223946.26784-4-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + hw/alpha/dp264.c | 3 ++- hw/i386/pc.c | 1 + hw/i386/vmmouse.c | 1 + hw/i386/vmport.c | 1 + hw/input/pckbd.c | 2 +- hw/mips/mips_fulong2e.c | 3 ++- hw/mips/mips_jazz.c | 1 + hw/mips/mips_malta.c | 3 ++- hw/mips/mips_r4k.c | 3 ++- hw/ppc/prep.c | 5 +++-- hw/sparc64/sun4u.c | 1 + hw/unicore32/puv3.c | 1 + include/hw/i386/pc.h | 9 --------- include/hw/input/i8042.h | 24 ++++++++++++++++++++++++ 15 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 include/hw/input/i8042.h diff --git a/MAINTAINERS b/MAINTAINERS index 319ac9f929..6703ac8c89 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -942,6 +942,7 @@ F: include/hw/display/vga.h F: include/hw/char/parallel.h F: include/hw/dma/i8257.h F: include/hw/i2c/pm_smbus.h +F: include/hw/input/i8042.h F: include/hw/timer/hpet.h F: include/hw/timer/i8254* F: include/hw/timer/mc146818rtc* diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 766373eec7..e13cb576fd 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -19,6 +19,7 @@ #include "hw/timer/mc146818rtc.h" #include "hw/ide.h" #include "hw/timer/i8254.h" +#include "hw/input/i8042.h" #include "hw/char/serial.h" #include "qemu/cutils.h" @@ -81,7 +82,7 @@ static void clipper_init(MachineState *machine) mc146818_rtc_init(isa_bus, 1900, rtc_irq); i8254_pit_init(isa_bus, 0x40, 0, NULL); - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); /* VGA setup. Don't bother loading the bios. */ pci_vga_init(pci_bus); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a6ceea9c64..853a01d791 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -43,6 +43,7 @@ #include "hw/timer/mc146818rtc.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" +#include "hw/input/i8042.h" #include "hw/audio/pcspk.h" #include "hw/pci/msi.h" #include "hw/sysbus.h" diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index 65ef55329e..5d2d278be4 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -25,6 +25,7 @@ #include "hw/hw.h" #include "ui/console.h" #include "hw/i386/pc.h" +#include "hw/input/i8042.h" #include "hw/qdev.h" /* debug only vmmouse */ diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 116aa09819..3bf8cfe041 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -25,6 +25,7 @@ #include "hw/hw.h" #include "hw/isa/isa.h" #include "hw/i386/pc.h" +#include "hw/input/i8042.h" #include "sysemu/hw_accel.h" #include "hw/qdev.h" #include "qemu/log.h" diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index c479f827b6..f17f18e51b 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -26,6 +26,7 @@ #include "hw/isa/isa.h" #include "hw/i386/pc.h" #include "hw/input/ps2.h" +#include "hw/input/i8042.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ @@ -480,7 +481,6 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, qemu_register_reset(kbd_reset, s); } -#define TYPE_I8042 "i8042" #define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042) typedef struct ISAKBDState { diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 1e43768589..a15d3b60cc 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -43,6 +43,7 @@ #include "hw/isa/vt82c686.h" #include "hw/timer/mc146818rtc.h" #include "hw/timer/i8254.h" +#include "hw/input/i8042.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" @@ -363,7 +364,7 @@ static void mips_fulong2e_init(MachineState *machine) i8257_dma_init(isa_bus, 0); /* Super I/O */ - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); mc146818_rtc_init(isa_bus, 2000, NULL); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 8b6f03a889..7223085547 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -43,6 +43,7 @@ #include "hw/timer/i8254.h" #include "hw/display/vga.h" #include "hw/audio/pcspk.h" +#include "hw/input/i8042.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 9cb86c432e..cd7bd0eef6 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -47,6 +47,7 @@ #include "hw/loader.h" #include "elf.h" #include "hw/timer/mc146818rtc.h" +#include "hw/input/i8042.h" #include "hw/timer/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" @@ -1213,7 +1214,7 @@ void mips_malta_init(MachineState *machine) i8257_dma_init(isa_bus, 0); /* Super I/O */ - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); mc146818_rtc_init(isa_bus, 2000, NULL); serial_hds_isa_init(isa_bus, 0, 2); diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 830ee7732c..aeadc4a340 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -28,6 +28,7 @@ #include "hw/loader.h" #include "elf.h" #include "hw/timer/mc146818rtc.h" +#include "hw/input/i8042.h" #include "hw/timer/i8254.h" #include "sysemu/block-backend.h" #include "exec/address-spaces.h" @@ -286,7 +287,7 @@ void mips_r4k_init(MachineState *machine) hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); } static void mips_machine_init(MachineClass *mc) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index c9d8950de7..85b4fae3c7 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -41,6 +41,7 @@ #include "hw/ide.h" #include "hw/loader.h" #include "hw/timer/mc146818rtc.h" +#include "hw/input/i8042.h" #include "hw/isa/pc87312.h" #include "hw/net/ne2000-isa.h" #include "sysemu/arch_init.h" @@ -640,7 +641,7 @@ static void ppc_prep_init(MachineState *machine) hd[2 * i], hd[2 * i + 1]); } - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); cpu = POWERPC_CPU(first_cpu); sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET]; @@ -770,7 +771,7 @@ static void ibm_40p_init(MachineState *machine) /* add some more devices */ if (defaults_enabled()) { - isa_create_simple(isa_bus, "i8042"); + isa_create_simple(isa_bus, TYPE_I8042); m48t59 = NVRAM(isa_create_simple(isa_bus, "isa-m48t59")); dev = DEVICE(isa_create(isa_bus, "cs4231a")); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 0ca0243821..2044a52ded 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -36,6 +36,7 @@ #include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/timer/m48t59.h" +#include "hw/input/i8042.h" #include "hw/block/fdc.h" #include "net/net.h" #include "qemu/timer.h" diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index db26959a1d..830fe3face 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -20,6 +20,7 @@ #undef DEBUG_PUV3 #include "hw/unicore32/puv3.h" +#include "hw/input/i8042.h" #define KERNEL_LOAD_ADDR 0x03000000 #define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 962ee7de0c..6598d571a0 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -189,15 +189,6 @@ void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque); void vmmouse_get_data(uint32_t *data); void vmmouse_set_data(const uint32_t *data); -/* pckbd.c */ -#define I8042_A20_LINE "a20" - -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, - MemoryRegion *region, ram_addr_t size, - hwaddr mask); -void i8042_isa_mouse_fake_event(void *opaque); -void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out); - /* pc.c */ extern int fd_bootchk; diff --git a/include/hw/input/i8042.h b/include/hw/input/i8042.h new file mode 100644 index 0000000000..f6ff146364 --- /dev/null +++ b/include/hw/input/i8042.h @@ -0,0 +1,24 @@ +/* + * QEMU PS/2 Controller + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: MIT + */ +#ifndef HW_INPUT_I8042_H +#define HW_INPUT_I8042_H + +#include "hw/hw.h" +#include "hw/isa/isa.h" + +#define TYPE_I8042 "i8042" + +#define I8042_A20_LINE "a20" + +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, + MemoryRegion *region, ram_addr_t size, + hwaddr mask); +void i8042_isa_mouse_fake_event(void *opaque); +void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out); + +#endif /* HW_INPUT_I8042_H */ -- cgit v1.2.1 From a48c6b5155bf542b14d6a6fc04f627eb2cb62967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:25 +0100 Subject: MAINTAINERS: Fix the PC87312 include path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missed while moving it in 0d09e41a51aa. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-5-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6703ac8c89..1ff22ce610 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -776,9 +776,10 @@ F: hw/ppc/prep_systemio.c F: hw/ppc/rs6000_mc.c F: hw/pci-host/prep.[hc] F: hw/isa/i82378.c -F: hw/isa/pc87312.[hc] +F: hw/isa/pc87312.c F: hw/dma/i82374.c F: hw/timer/m48t59-isa.c +F: include/hw/isa/pc87312.h F: include/hw/timer/m48t59.h F: pc-bios/ppc_rom.bin -- cgit v1.2.1 From 010d2dc4731d00d6c8e05ad333104d258180c19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:26 +0100 Subject: hw/isa/pc87312: Rename the device type as TYPE_PC87312_SUPERIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: David Gibson (hw/ppc) Message-Id: <20180308223946.26784-6-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- hw/isa/pc87312.c | 2 +- hw/ppc/prep.c | 2 +- include/hw/isa/pc87312.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 48b29e3c3c..e9edbc6c50 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -391,7 +391,7 @@ static void pc87312_class_init(ObjectClass *klass, void *data) } static const TypeInfo pc87312_type_info = { - .name = TYPE_PC87312, + .name = TYPE_PC87312_SUPERIO, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PC87312State), .instance_init = pc87312_initfn, diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 85b4fae3c7..df774bd384 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -612,7 +612,7 @@ static void ppc_prep_init(MachineState *machine) isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci), "isa.0")); /* Super I/O (parallel + serial ports) */ - isa = isa_create(isa_bus, TYPE_PC87312); + isa = isa_create(isa_bus, TYPE_PC87312_SUPERIO); dev = DEVICE(isa); qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */ qdev_init_nofail(dev); diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index bf74470d40..710eb1c807 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -28,8 +28,8 @@ #include "hw/isa/isa.h" -#define TYPE_PC87312 "pc87312" -#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312) +#define TYPE_PC87312_SUPERIO "pc87312" +#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312_SUPERIO) typedef struct PC87312State { ISADevice dev; -- cgit v1.2.1 From 4e00105a76c9c3502ca1fec0c73ea3f57b72f21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:27 +0100 Subject: hw/isa/pc87312: Use uint16_t for the ISA I/O base address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This matches the isa_register_ioport() prototype. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-7-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/pc87312.c | 14 +++++++------- include/hw/isa/pc87312.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index e9edbc6c50..105c23e680 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -69,9 +69,9 @@ static inline bool is_parallel_enabled(PC87312State *s) return s->regs[REG_FER] & FER_PARALLEL_EN; } -static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; +static const uint16_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; -static inline uint32_t get_parallel_iobase(PC87312State *s) +static inline uint16_t get_parallel_iobase(PC87312State *s) { return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR]; } @@ -92,12 +92,12 @@ static inline uint32_t get_parallel_irq(PC87312State *s) /* UARTs */ -static const uint32_t uart_base[2][4] = { +static const uint16_t uart_base[2][4] = { { 0x3e8, 0x338, 0x2e8, 0x220 }, { 0x2e8, 0x238, 0x2e0, 0x228 } }; -static inline uint32_t get_uart_iobase(PC87312State *s, int i) +static inline uint16_t get_uart_iobase(PC87312State *s, int i) { int idx; idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; @@ -130,7 +130,7 @@ static inline bool is_fdc_enabled(PC87312State *s) return s->regs[REG_FER] & FER_FDC_EN; } -static inline uint32_t get_fdc_iobase(PC87312State *s) +static inline uint16_t get_fdc_iobase(PC87312State *s) { return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0; } @@ -143,7 +143,7 @@ static inline bool is_ide_enabled(PC87312State *s) return s->regs[REG_FER] & FER_IDE_EN; } -static inline uint32_t get_ide_iobase(PC87312State *s) +static inline uint16_t get_ide_iobase(PC87312State *s) { return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0; } @@ -373,7 +373,7 @@ static const VMStateDescription vmstate_pc87312 = { }; static Property pc87312_properties[] = { - DEFINE_PROP_UINT32("iobase", PC87312State, iobase, 0x398), + DEFINE_PROP_UINT16("iobase", PC87312State, iobase, 0x398), DEFINE_PROP_UINT8("config", PC87312State, config, 1), DEFINE_PROP_END_OF_LIST() }; diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index 710eb1c807..b65b219a8a 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -34,7 +34,7 @@ typedef struct PC87312State { ISADevice dev; - uint32_t iobase; + uint16_t iobase; uint8_t config; /* initial configuration */ struct { -- cgit v1.2.1 From 818c9d992f5b8db2c46f9171ec69055f1b0bdf5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:28 +0100 Subject: hw/isa/pc87312: Use 'unsigned int' for the irq value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-8-f4bug@amsat.org> Reviewed-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- hw/isa/pc87312.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 105c23e680..fda91fed21 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -76,9 +76,9 @@ static inline uint16_t get_parallel_iobase(PC87312State *s) return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR]; } -static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; +static const unsigned int parallel_irq[] = { 5, 7, 5, 0 }; -static inline uint32_t get_parallel_irq(PC87312State *s) +static inline unsigned int get_parallel_irq(PC87312State *s) { int idx; idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR); @@ -110,7 +110,7 @@ static inline uint16_t get_uart_iobase(PC87312State *s, int i) } } -static inline uint32_t get_uart_irq(PC87312State *s, int i) +static inline unsigned int get_uart_irq(PC87312State *s, int i) { int idx; idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; -- cgit v1.2.1 From 1854eb287e77c07b2089b42319e23c7c0df8a2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:29 +0100 Subject: hw/isa/superio: Add a Super I/O template based on the PC87312 device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-9-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ hw/isa/Makefile.objs | 1 + hw/isa/isa-superio.c | 28 ++++++++++++++++++++++++++++ include/hw/isa/superio.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 hw/isa/isa-superio.c create mode 100644 include/hw/isa/superio.h diff --git a/MAINTAINERS b/MAINTAINERS index 1ff22ce610..9f7b8e79c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -933,6 +933,7 @@ F: hw/input/pckbd.c F: hw/intc/apic* F: hw/intc/ioapic* F: hw/intc/i8259* +F: hw/isa/isa-superio.c F: hw/misc/debugexit.c F: hw/misc/pc-testdev.c F: hw/timer/hpet* @@ -944,6 +945,7 @@ F: include/hw/char/parallel.h F: include/hw/dma/i8257.h F: include/hw/i2c/pm_smbus.h F: include/hw/input/i8042.h +F: include/hw/isa/superio.h F: include/hw/timer/hpet.h F: include/hw/timer/i8254* F: include/hw/timer/mc146818rtc* diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index fb37c55cf2..cac655ba58 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -1,4 +1,5 @@ common-obj-$(CONFIG_ISA_BUS) += isa-bus.o +common-obj-$(CONFIG_ISA_BUS) += isa-superio.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o common-obj-$(CONFIG_PC87312) += pc87312.o diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c new file mode 100644 index 0000000000..14ec16f831 --- /dev/null +++ b/hw/isa/isa-superio.c @@ -0,0 +1,28 @@ +/* + * Generic ISA Super I/O + * + * Copyright (c) 2010-2012 Herve Poussineau + * Copyright (c) 2011-2012 Andreas Färber + * Copyright (c) 2018 Philippe Mathieu-Daudé + * + * This code is licensed under the GNU GPLv2 and later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "hw/isa/superio.h" +#include "trace.h" + +static const TypeInfo isa_superio_type_info = { + .name = TYPE_ISA_SUPERIO, + .parent = TYPE_ISA_DEVICE, + .abstract = true, + .class_size = sizeof(ISASuperIOClass), +}; + +static void isa_superio_register_types(void) +{ + type_register_static(&isa_superio_type_info); +} + +type_init(isa_superio_register_types) diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h new file mode 100644 index 0000000000..cff6ad6c08 --- /dev/null +++ b/include/hw/isa/superio.h @@ -0,0 +1,44 @@ +/* + * Generic ISA Super I/O + * + * Copyright (c) 2018 Philippe Mathieu-Daudé + * + * This code is licensed under the GNU GPLv2 and later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_ISA_SUPERIO_H +#define HW_ISA_SUPERIO_H + +#include "qemu-common.h" +#include "sysemu/sysemu.h" +#include "hw/isa/isa.h" + +#define TYPE_ISA_SUPERIO "isa-superio" +#define ISA_SUPERIO(obj) \ + OBJECT_CHECK(ISASuperIODevice, (obj), TYPE_ISA_SUPERIO) +#define ISA_SUPERIO_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ISASuperIOClass, (obj), TYPE_ISA_SUPERIO) +#define ISA_SUPERIO_CLASS(klass) \ + OBJECT_CLASS_CHECK(ISASuperIOClass, (klass), TYPE_ISA_SUPERIO) + +typedef struct ISASuperIODevice { + ISADevice parent_obj; +} ISASuperIODevice; + +typedef struct ISASuperIOFuncs { + size_t count; + bool (*is_enabled)(ISASuperIODevice *sio, uint8_t index); + uint16_t (*get_iobase)(ISASuperIODevice *sio, uint8_t index); + unsigned int (*get_irq)(ISASuperIODevice *sio, uint8_t index); + unsigned int (*get_dma)(ISASuperIODevice *sio, uint8_t index); +} ISASuperIOFuncs; + +typedef struct ISASuperIOClass { + /*< private >*/ + ISADeviceClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; +} ISASuperIOClass; + +#endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From 63f01a74aeeb9c4fb39e2b4100beb084f5c10c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:30 +0100 Subject: hw/isa/pc87312: Inherit from the abstract TYPE_ISA_SUPERIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-10-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/pc87312.c | 11 ++++++++++- include/hw/isa/pc87312.h | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index fda91fed21..6b8100ff56 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -270,6 +270,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp) ISABus *bus; Chardev *chr; DriveInfo *drive; + Error *local_err = NULL; char name[5]; int i; @@ -279,6 +280,12 @@ static void pc87312_realize(DeviceState *dev, Error **errp) isa_register_ioport(isa, &s->io, s->iobase); pc87312_hard_reset(s); + ISA_SUPERIO_GET_CLASS(dev)->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (is_parallel_enabled(s)) { /* FIXME use a qdev chardev prop instead of parallel_hds[] */ chr = parallel_hds[0]; @@ -381,7 +388,9 @@ static Property pc87312_properties[] = { static void pc87312_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + sc->parent_realize = dc->realize; dc->realize = pc87312_realize; dc->reset = pc87312_reset; dc->vmsd = &vmstate_pc87312; @@ -392,7 +401,7 @@ static void pc87312_class_init(ObjectClass *klass, void *data) static const TypeInfo pc87312_type_info = { .name = TYPE_PC87312_SUPERIO, - .parent = TYPE_ISA_DEVICE, + .parent = TYPE_ISA_SUPERIO, .instance_size = sizeof(PC87312State), .instance_init = pc87312_initfn, .class_init = pc87312_class_init, diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index b65b219a8a..f3761d6fe1 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -25,14 +25,16 @@ #ifndef QEMU_PC87312_H #define QEMU_PC87312_H -#include "hw/isa/isa.h" +#include "hw/isa/superio.h" #define TYPE_PC87312_SUPERIO "pc87312" #define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312_SUPERIO) typedef struct PC87312State { - ISADevice dev; + /*< private >*/ + ISASuperIODevice parent_dev; + /*< public >*/ uint16_t iobase; uint8_t config; /* initial configuration */ -- cgit v1.2.1 From 4c3119a6e3ea7bdab718015b6f5176cfaf52f7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:31 +0100 Subject: hw/isa/superio: Factor out the parallel code from pc87312.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-11-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/isa/pc87312.c | 38 +++++++++++----------------- hw/isa/trace-events | 4 ++- include/hw/isa/pc87312.h | 4 --- include/hw/isa/superio.h | 6 +++++ 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 14ec16f831..eb263fcc3a 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -10,14 +10,79 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "chardev/char.h" #include "hw/isa/superio.h" #include "trace.h" +static void isa_superio_realize(DeviceState *dev, Error **errp) +{ + ISASuperIODevice *sio = ISA_SUPERIO(dev); + ISASuperIOClass *k = ISA_SUPERIO_GET_CLASS(sio); + ISABus *bus = isa_bus_from_device(ISA_DEVICE(dev)); + ISADevice *isa; + DeviceState *d; + Chardev *chr; + char *name; + int i; + + /* Parallel port */ + for (i = 0; i < k->parallel.count; i++) { + if (i >= ARRAY_SIZE(sio->parallel)) { + warn_report("superio: ignoring %td parallel controllers", + k->parallel.count - ARRAY_SIZE(sio->parallel)); + break; + } + if (!k->parallel.is_enabled || k->parallel.is_enabled(sio, i)) { + /* FIXME use a qdev chardev prop instead of parallel_hds[] */ + chr = parallel_hds[i]; + if (chr == NULL || chr->be) { + name = g_strdup_printf("discarding-parallel%d", i); + chr = qemu_chr_new(name, "null"); + } else { + name = g_strdup_printf("parallel%d", i); + } + isa = isa_create(bus, "isa-parallel"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", i); + if (k->parallel.get_iobase) { + qdev_prop_set_uint32(d, "iobase", + k->parallel.get_iobase(sio, i)); + } + if (k->parallel.get_irq) { + qdev_prop_set_uint32(d, "irq", k->parallel.get_irq(sio, i)); + } + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + sio->parallel[i] = isa; + trace_superio_create_parallel(i, + k->parallel.get_iobase ? + k->parallel.get_iobase(sio, i) : -1, + k->parallel.get_irq ? + k->parallel.get_irq(sio, i) : -1); + object_property_add_child(OBJECT(dev), name, + OBJECT(sio->parallel[i]), NULL); + g_free(name); + } + } +} + +static void isa_superio_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = isa_superio_realize; + /* Reason: Uses parallel_hds[0] in realize(), so it can't be used twice */ + dc->user_creatable = false; +} + static const TypeInfo isa_superio_type_info = { .name = TYPE_ISA_SUPERIO, .parent = TYPE_ISA_DEVICE, .abstract = true, .class_size = sizeof(ISASuperIOClass), + .class_init = isa_superio_class_init, }; static void isa_superio_register_types(void) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 6b8100ff56..1c15715c69 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -64,22 +64,25 @@ /* Parallel port */ -static inline bool is_parallel_enabled(PC87312State *s) +static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index) { - return s->regs[REG_FER] & FER_PARALLEL_EN; + PC87312State *s = PC87312(sio); + return index ? false : s->regs[REG_FER] & FER_PARALLEL_EN; } static const uint16_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; -static inline uint16_t get_parallel_iobase(PC87312State *s) +static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR]; } static const unsigned int parallel_irq[] = { 5, 7, 5, 0 }; -static inline unsigned int get_parallel_irq(PC87312State *s) +static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); int idx; idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR); if (idx == 0) { @@ -286,24 +289,6 @@ static void pc87312_realize(DeviceState *dev, Error **errp) return; } - if (is_parallel_enabled(s)) { - /* FIXME use a qdev chardev prop instead of parallel_hds[] */ - chr = parallel_hds[0]; - if (chr == NULL) { - chr = qemu_chr_new("par0", "null"); - } - isa = isa_create(bus, "isa-parallel"); - d = DEVICE(isa); - qdev_prop_set_uint32(d, "index", 0); - qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s)); - qdev_prop_set_uint32(d, "irq", get_parallel_irq(s)); - qdev_prop_set_chr(d, "chardev", chr); - qdev_init_nofail(d); - s->parallel.dev = isa; - trace_pc87312_info_parallel(get_parallel_iobase(s), - get_parallel_irq(s)); - } - for (i = 0; i < 2; i++) { if (is_uart_enabled(s, i)) { /* FIXME use a qdev chardev prop instead of serial_hds[] */ @@ -395,8 +380,15 @@ static void pc87312_class_init(ObjectClass *klass, void *data) dc->reset = pc87312_reset; dc->vmsd = &vmstate_pc87312; dc->props = pc87312_properties; - /* Reason: Uses parallel_hds[0] in realize(), so it can't be used twice */ + /* Reason: Uses serial_hds[0] in realize(), so it can't be used twice */ dc->user_creatable = false; + + sc->parallel = (ISASuperIOFuncs){ + .count = 1, + .is_enabled = is_parallel_enabled, + .get_iobase = get_parallel_iobase, + .get_irq = get_parallel_irq, + }; } static const TypeInfo pc87312_type_info = { diff --git a/hw/isa/trace-events b/hw/isa/trace-events index a4ab4e3634..97b1949981 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -1,9 +1,11 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/isa/isa-superio.c +superio_create_parallel(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" + # hw/isa/pc87312.c pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" pc87312_info_floppy(uint32_t base) "base 0x%x" pc87312_info_ide(uint32_t base) "base 0x%x" -pc87312_info_parallel(uint32_t base, uint32_t irq) "base 0x%x, irq %u" pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u" diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index f3761d6fe1..bcc4578479 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -39,10 +39,6 @@ typedef struct PC87312State { uint16_t iobase; uint8_t config; /* initial configuration */ - struct { - ISADevice *dev; - } parallel; - struct { ISADevice *dev; } uart[2]; diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index cff6ad6c08..e9879cfde1 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -23,7 +23,11 @@ OBJECT_CLASS_CHECK(ISASuperIOClass, (klass), TYPE_ISA_SUPERIO) typedef struct ISASuperIODevice { + /*< private >*/ ISADevice parent_obj; + /*< public >*/ + + ISADevice *parallel[MAX_PARALLEL_PORTS]; } ISASuperIODevice; typedef struct ISASuperIOFuncs { @@ -39,6 +43,8 @@ typedef struct ISASuperIOClass { ISADeviceClass parent_class; /*< public >*/ DeviceRealize parent_realize; + + ISASuperIOFuncs parallel; } ISASuperIOClass; #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From cd9526ab7c04f2c32c63340b04401f6ed25682b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:32 +0100 Subject: hw/isa/superio: Factor out the serial code from pc87312.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-12-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 41 +++++++++++++++++++++++++++++++++++++++++ hw/isa/pc87312.c | 43 ++++++++++++------------------------------- hw/isa/trace-events | 2 +- include/hw/isa/pc87312.h | 4 ---- include/hw/isa/superio.h | 2 ++ 5 files changed, 56 insertions(+), 36 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index eb263fcc3a..6962421aad 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -14,6 +14,7 @@ #include "sysemu/sysemu.h" #include "chardev/char.h" #include "hw/isa/superio.h" +#include "hw/char/serial.h" #include "trace.h" static void isa_superio_realize(DeviceState *dev, Error **errp) @@ -66,6 +67,46 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) g_free(name); } } + + /* Serial */ + for (i = 0; i < k->serial.count; i++) { + if (i >= ARRAY_SIZE(sio->serial)) { + warn_report("superio: ignoring %td serial controllers", + k->serial.count - ARRAY_SIZE(sio->serial)); + break; + } + if (!k->serial.is_enabled || k->serial.is_enabled(sio, i)) { + /* FIXME use a qdev chardev prop instead of serial_hds[] */ + chr = serial_hds[i]; + if (chr == NULL || chr->be) { + name = g_strdup_printf("discarding-serial%d", i); + chr = qemu_chr_new(name, "null"); + } else { + name = g_strdup_printf("serial%d", i); + } + isa = isa_create(bus, TYPE_ISA_SERIAL); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", i); + if (k->serial.get_iobase) { + qdev_prop_set_uint32(d, "iobase", + k->serial.get_iobase(sio, i)); + } + if (k->serial.get_irq) { + qdev_prop_set_uint32(d, "irq", k->serial.get_irq(sio, i)); + } + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + sio->serial[i] = isa; + trace_superio_create_serial(i, + k->serial.get_iobase ? + k->serial.get_iobase(sio, i) : -1, + k->serial.get_irq ? + k->serial.get_irq(sio, i) : -1); + object_property_add_child(OBJECT(dev), name, + OBJECT(sio->serial[0]), NULL); + g_free(name); + } + } } static void isa_superio_class_init(ObjectClass *oc, void *data) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 1c15715c69..c2837bca43 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -29,8 +29,6 @@ #include "qemu/error-report.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" -#include "sysemu/sysemu.h" -#include "chardev/char.h" #include "trace.h" @@ -100,8 +98,9 @@ static const uint16_t uart_base[2][4] = { { 0x2e8, 0x238, 0x2e0, 0x228 } }; -static inline uint16_t get_uart_iobase(PC87312State *s, int i) +static uint16_t get_uart_iobase(ISASuperIODevice *sio, uint8_t i) { + PC87312State *s = PC87312(sio); int idx; idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; if (idx == 0) { @@ -113,15 +112,17 @@ static inline uint16_t get_uart_iobase(PC87312State *s, int i) } } -static inline unsigned int get_uart_irq(PC87312State *s, int i) +static unsigned int get_uart_irq(ISASuperIODevice *sio, uint8_t i) { + PC87312State *s = PC87312(sio); int idx; idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; return (idx & 1) ? 3 : 4; } -static inline bool is_uart_enabled(PC87312State *s, int i) +static bool is_uart_enabled(ISASuperIODevice *sio, uint8_t i) { + PC87312State *s = PC87312(sio); return s->regs[REG_FER] & (FER_UART1_EN << i); } @@ -271,11 +272,8 @@ static void pc87312_realize(DeviceState *dev, Error **errp) DeviceState *d; ISADevice *isa; ISABus *bus; - Chardev *chr; DriveInfo *drive; Error *local_err = NULL; - char name[5]; - int i; s = PC87312(dev); isa = ISA_DEVICE(dev); @@ -289,27 +287,6 @@ static void pc87312_realize(DeviceState *dev, Error **errp) return; } - for (i = 0; i < 2; i++) { - if (is_uart_enabled(s, i)) { - /* FIXME use a qdev chardev prop instead of serial_hds[] */ - chr = serial_hds[i]; - if (chr == NULL) { - snprintf(name, sizeof(name), "ser%d", i); - chr = qemu_chr_new(name, "null"); - } - isa = isa_create(bus, "isa-serial"); - d = DEVICE(isa); - qdev_prop_set_uint32(d, "index", i); - qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i)); - qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i)); - qdev_prop_set_chr(d, "chardev", chr); - qdev_init_nofail(d); - s->uart[i].dev = isa; - trace_pc87312_info_serial(i, get_uart_iobase(s, i), - get_uart_irq(s, i)); - } - } - if (is_fdc_enabled(s)) { isa = isa_create(bus, "isa-fdc"); d = DEVICE(isa); @@ -380,8 +357,6 @@ static void pc87312_class_init(ObjectClass *klass, void *data) dc->reset = pc87312_reset; dc->vmsd = &vmstate_pc87312; dc->props = pc87312_properties; - /* Reason: Uses serial_hds[0] in realize(), so it can't be used twice */ - dc->user_creatable = false; sc->parallel = (ISASuperIOFuncs){ .count = 1, @@ -389,6 +364,12 @@ static void pc87312_class_init(ObjectClass *klass, void *data) .get_iobase = get_parallel_iobase, .get_irq = get_parallel_irq, }; + sc->serial = (ISASuperIOFuncs){ + .count = 2, + .is_enabled = is_uart_enabled, + .get_iobase = get_uart_iobase, + .get_irq = get_uart_irq, + }; } static const TypeInfo pc87312_type_info = { diff --git a/hw/isa/trace-events b/hw/isa/trace-events index 97b1949981..c78dd6c353 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -2,10 +2,10 @@ # hw/isa/isa-superio.c superio_create_parallel(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" +superio_create_serial(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" # hw/isa/pc87312.c pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" pc87312_info_floppy(uint32_t base) "base 0x%x" pc87312_info_ide(uint32_t base) "base 0x%x" -pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u" diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index bcc4578479..1480615a2c 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -39,10 +39,6 @@ typedef struct PC87312State { uint16_t iobase; uint8_t config; /* initial configuration */ - struct { - ISADevice *dev; - } uart[2]; - struct { ISADevice *dev; } fdc; diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index e9879cfde1..0b516721c3 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -28,6 +28,7 @@ typedef struct ISASuperIODevice { /*< public >*/ ISADevice *parallel[MAX_PARALLEL_PORTS]; + ISADevice *serial[MAX_SERIAL_PORTS]; } ISASuperIODevice; typedef struct ISASuperIOFuncs { @@ -45,6 +46,7 @@ typedef struct ISASuperIOClass { DeviceRealize parent_realize; ISASuperIOFuncs parallel; + ISASuperIOFuncs serial; } ISASuperIOClass; #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From 6f6695b13638b0a4bfd9f75c022a9a7c55fb0b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:33 +0100 Subject: hw/isa/superio: Factor out the floppy disc controller code from pc87312.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-13-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 36 ++++++++++++++++++++++++++++++++++++ hw/isa/pc87312.c | 46 +++++++++++++++++++--------------------------- hw/isa/trace-events | 2 +- include/hw/isa/pc87312.h | 4 ---- include/hw/isa/superio.h | 2 ++ 5 files changed, 58 insertions(+), 32 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 6962421aad..4b5e280b38 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -11,7 +11,10 @@ */ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" +#include "sysemu/blockdev.h" #include "chardev/char.h" #include "hw/isa/superio.h" #include "hw/char/serial.h" @@ -25,6 +28,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) ISADevice *isa; DeviceState *d; Chardev *chr; + DriveInfo *drive; char *name; int i; @@ -107,6 +111,38 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) g_free(name); } } + + /* Floppy disc */ + if (!k->floppy.is_enabled || k->floppy.is_enabled(sio, 0)) { + isa = isa_create(bus, "isa-fdc"); + d = DEVICE(isa); + if (k->floppy.get_iobase) { + qdev_prop_set_uint32(d, "iobase", k->floppy.get_iobase(sio, 0)); + } + if (k->floppy.get_irq) { + qdev_prop_set_uint32(d, "irq", k->floppy.get_irq(sio, 0)); + } + /* FIXME use a qdev drive property instead of drive_get() */ + drive = drive_get(IF_FLOPPY, 0, 0); + if (drive != NULL) { + qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive), + &error_fatal); + } + /* FIXME use a qdev drive property instead of drive_get() */ + drive = drive_get(IF_FLOPPY, 0, 1); + if (drive != NULL) { + qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), + &error_fatal); + } + qdev_init_nofail(d); + sio->floppy = isa; + trace_superio_create_floppy(0, + k->floppy.get_iobase ? + k->floppy.get_iobase(sio, 0) : -1, + k->floppy.get_irq ? + k->floppy.get_irq(sio, 0) : -1); + } + } static void isa_superio_class_init(ObjectClass *oc, void *data) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index c2837bca43..a1845a91c3 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -27,8 +27,6 @@ #include "hw/isa/pc87312.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" #include "trace.h" @@ -129,16 +127,26 @@ static bool is_uart_enabled(ISASuperIODevice *sio, uint8_t i) /* Floppy controller */ -static inline bool is_fdc_enabled(PC87312State *s) +static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); + assert(!index); return s->regs[REG_FER] & FER_FDC_EN; } -static inline uint16_t get_fdc_iobase(PC87312State *s) +static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); + assert(!index); return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0; } +static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index) +{ + assert(!index); + return 6; +} + /* IDE controller */ @@ -272,7 +280,6 @@ static void pc87312_realize(DeviceState *dev, Error **errp) DeviceState *d; ISADevice *isa; ISABus *bus; - DriveInfo *drive; Error *local_err = NULL; s = PC87312(dev); @@ -287,28 +294,6 @@ static void pc87312_realize(DeviceState *dev, Error **errp) return; } - if (is_fdc_enabled(s)) { - isa = isa_create(bus, "isa-fdc"); - d = DEVICE(isa); - qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s)); - qdev_prop_set_uint32(d, "irq", 6); - /* FIXME use a qdev drive property instead of drive_get() */ - drive = drive_get(IF_FLOPPY, 0, 0); - if (drive != NULL) { - qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive), - &error_fatal); - } - /* FIXME use a qdev drive property instead of drive_get() */ - drive = drive_get(IF_FLOPPY, 0, 1); - if (drive != NULL) { - qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), - &error_fatal); - } - qdev_init_nofail(d); - s->fdc.dev = isa; - trace_pc87312_info_floppy(get_fdc_iobase(s)); - } - if (is_ide_enabled(s)) { isa = isa_create(bus, "isa-ide"); d = DEVICE(isa); @@ -370,6 +355,12 @@ static void pc87312_class_init(ObjectClass *klass, void *data) .get_iobase = get_uart_iobase, .get_irq = get_uart_irq, }; + sc->floppy = (ISASuperIOFuncs){ + .count = 1, + .is_enabled = is_fdc_enabled, + .get_iobase = get_fdc_iobase, + .get_irq = get_fdc_irq, + }; } static const TypeInfo pc87312_type_info = { @@ -378,6 +369,7 @@ static const TypeInfo pc87312_type_info = { .instance_size = sizeof(PC87312State), .instance_init = pc87312_initfn, .class_init = pc87312_class_init, + /* FIXME use a qdev drive property instead of drive_get() */ }; static void pc87312_register_types(void) diff --git a/hw/isa/trace-events b/hw/isa/trace-events index c78dd6c353..8d9900882f 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -3,9 +3,9 @@ # hw/isa/isa-superio.c superio_create_parallel(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" superio_create_serial(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" +superio_create_floppy(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" # hw/isa/pc87312.c pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" -pc87312_info_floppy(uint32_t base) "base 0x%x" pc87312_info_ide(uint32_t base) "base 0x%x" diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h index 1480615a2c..e16263d4b1 100644 --- a/include/hw/isa/pc87312.h +++ b/include/hw/isa/pc87312.h @@ -39,10 +39,6 @@ typedef struct PC87312State { uint16_t iobase; uint8_t config; /* initial configuration */ - struct { - ISADevice *dev; - } fdc; - struct { ISADevice *dev; } ide; diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index 0b516721c3..e8007b9eee 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -29,6 +29,7 @@ typedef struct ISASuperIODevice { ISADevice *parallel[MAX_PARALLEL_PORTS]; ISADevice *serial[MAX_SERIAL_PORTS]; + ISADevice *floppy; } ISASuperIODevice; typedef struct ISASuperIOFuncs { @@ -47,6 +48,7 @@ typedef struct ISASuperIOClass { ISASuperIOFuncs parallel; ISASuperIOFuncs serial; + ISASuperIOFuncs floppy; } ISASuperIOClass; #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From 72d3d8f052a19abc455ddc88efef75c407ac7c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:34 +0100 Subject: hw/isa/superio: Add a keyboard/mouse controller (8042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the PC87312 inherits this abstract model, we remove the I8042 instance in the PREP machine. Signed-off-by: Philippe Mathieu-Daudé Acked-by: David Gibson Message-Id: <20180308223946.26784-14-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 3 +++ hw/ppc/prep.c | 1 - include/hw/isa/superio.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 4b5e280b38..041b47bdbf 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -17,6 +17,7 @@ #include "sysemu/blockdev.h" #include "chardev/char.h" #include "hw/isa/superio.h" +#include "hw/input/i8042.h" #include "hw/char/serial.h" #include "trace.h" @@ -143,6 +144,8 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) k->floppy.get_irq(sio, 0) : -1); } + /* Keyboard, mouse */ + sio->kbc = isa_create_simple(bus, TYPE_I8042); } static void isa_superio_class_init(ObjectClass *oc, void *data) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index df774bd384..5c78503069 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -641,7 +641,6 @@ static void ppc_prep_init(MachineState *machine) hd[2 * i], hd[2 * i + 1]); } - isa_create_simple(isa_bus, TYPE_I8042); cpu = POWERPC_CPU(first_cpu); sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET]; diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index e8007b9eee..2fc33bf3d3 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -30,6 +30,7 @@ typedef struct ISASuperIODevice { ISADevice *parallel[MAX_PARALLEL_PORTS]; ISADevice *serial[MAX_SERIAL_PORTS]; ISADevice *floppy; + ISADevice *kbc; } ISASuperIODevice; typedef struct ISASuperIOFuncs { -- cgit v1.2.1 From c16a4e1bc5e76a65cfa38266a1d9e88806b4bddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:35 +0100 Subject: hw/isa/superio: Factor out the IDE code from pc87312.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-15-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 22 ++++++++++++++++++++++ hw/isa/pc87312.c | 36 ++++++++++++++++++++---------------- hw/isa/trace-events | 2 +- include/hw/isa/superio.h | 2 ++ 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 041b47bdbf..f98711beff 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -146,6 +146,28 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) /* Keyboard, mouse */ sio->kbc = isa_create_simple(bus, TYPE_I8042); + + /* IDE */ + if (k->ide.count && (!k->ide.is_enabled || k->ide.is_enabled(sio, 0))) { + isa = isa_create(bus, "isa-ide"); + d = DEVICE(isa); + if (k->ide.get_iobase) { + qdev_prop_set_uint32(d, "iobase", k->ide.get_iobase(sio, 0)); + } + if (k->ide.get_iobase) { + qdev_prop_set_uint32(d, "iobase2", k->ide.get_iobase(sio, 1)); + } + if (k->ide.get_irq) { + qdev_prop_set_uint32(d, "irq", k->ide.get_irq(sio, 0)); + } + qdev_init_nofail(d); + sio->ide = isa; + trace_superio_create_ide(0, + k->ide.get_iobase ? + k->ide.get_iobase(sio, 0) : -1, + k->ide.get_irq ? + k->ide.get_irq(sio, 0) : -1); + } } static void isa_superio_class_init(ObjectClass *oc, void *data) diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index a1845a91c3..5cf64505fe 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -150,16 +150,28 @@ static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index) /* IDE controller */ -static inline bool is_ide_enabled(PC87312State *s) +static bool is_ide_enabled(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); + return s->regs[REG_FER] & FER_IDE_EN; } -static inline uint16_t get_ide_iobase(PC87312State *s) +static uint16_t get_ide_iobase(ISASuperIODevice *sio, uint8_t index) { + PC87312State *s = PC87312(sio); + + if (index == 1) { + return get_ide_iobase(sio, 0) + 0x206; + } return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0; } +static unsigned int get_ide_irq(ISASuperIODevice *sio, uint8_t index) +{ + assert(index == 0); + return 14; +} static void reconfigure_devices(PC87312State *s) { @@ -277,14 +289,11 @@ static void pc87312_reset(DeviceState *d) static void pc87312_realize(DeviceState *dev, Error **errp) { PC87312State *s; - DeviceState *d; ISADevice *isa; - ISABus *bus; Error *local_err = NULL; s = PC87312(dev); isa = ISA_DEVICE(dev); - bus = isa_bus_from_device(isa); isa_register_ioport(isa, &s->io, s->iobase); pc87312_hard_reset(s); @@ -293,17 +302,6 @@ static void pc87312_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - - if (is_ide_enabled(s)) { - isa = isa_create(bus, "isa-ide"); - d = DEVICE(isa); - qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s)); - qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206); - qdev_prop_set_uint32(d, "irq", 14); - qdev_init_nofail(d); - s->ide.dev = isa; - trace_pc87312_info_ide(get_ide_iobase(s)); - } } static void pc87312_initfn(Object *obj) @@ -361,6 +359,12 @@ static void pc87312_class_init(ObjectClass *klass, void *data) .get_iobase = get_fdc_iobase, .get_irq = get_fdc_irq, }; + sc->ide = (ISASuperIOFuncs){ + .count = 1, + .is_enabled = is_ide_enabled, + .get_iobase = get_ide_iobase, + .get_irq = get_ide_irq, + }; } static const TypeInfo pc87312_type_info = { diff --git a/hw/isa/trace-events b/hw/isa/trace-events index 8d9900882f..80ac6175d6 100644 --- a/hw/isa/trace-events +++ b/hw/isa/trace-events @@ -4,8 +4,8 @@ superio_create_parallel(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" superio_create_serial(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" superio_create_floppy(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" +superio_create_ide(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u" # hw/isa/pc87312.c pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" -pc87312_info_ide(uint32_t base) "base 0x%x" diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index 2fc33bf3d3..3dd5448f8c 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -31,6 +31,7 @@ typedef struct ISASuperIODevice { ISADevice *serial[MAX_SERIAL_PORTS]; ISADevice *floppy; ISADevice *kbc; + ISADevice *ide; } ISASuperIODevice; typedef struct ISASuperIOFuncs { @@ -50,6 +51,7 @@ typedef struct ISASuperIOClass { ISASuperIOFuncs parallel; ISASuperIOFuncs serial; ISASuperIOFuncs floppy; + ISASuperIOFuncs ide; } ISASuperIOClass; #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From 78f16256c157394522b0abae1dda0bfcbb11c068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:36 +0100 Subject: hw/mips/malta: Code movement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the SouthBridge peripherals first, and keep the Super I/O peripherals last. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-16-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/mips/mips_malta.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index cd7bd0eef6..9e0724ca5a 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1062,10 +1062,6 @@ void mips_malta_init(MachineState *machine) memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio); } - /* generate SPD EEPROM data */ - generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); - generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]); - #ifdef TARGET_WORDS_BIGENDIAN be = 1; #else @@ -1208,15 +1204,19 @@ void mips_malta_init(MachineState *machine) pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci"); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(NULL, 9), NULL, 0, NULL); - smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); - g_free(smbus_eeprom_buf); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); i8257_dma_init(isa_bus, 0); + mc146818_rtc_init(isa_bus, 2000, NULL); + + /* generate SPD EEPROM data */ + generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); + generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]); + smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); + g_free(smbus_eeprom_buf); /* Super I/O */ isa_create_simple(isa_bus, TYPE_I8042); - mc146818_rtc_init(isa_bus, 2000, NULL); serial_hds_isa_init(isa_bus, 0, 2); parallel_hds_isa_init(isa_bus, 1); -- cgit v1.2.1 From 7313b1f28bec390d03ec4b84146fbea43487f2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:37 +0100 Subject: hw/isa/superio: Factor out the FDC37M817 Super I/O from mips_malta.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-17-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/isa-superio.c | 19 +++++++++++++++++++ hw/mips/mips_malta.c | 35 ++++++++++------------------------- include/hw/isa/superio.h | 2 ++ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index f98711beff..b95608a003 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -187,9 +187,28 @@ static const TypeInfo isa_superio_type_info = { .class_init = isa_superio_class_init, }; +/* SMS FDC37M817 Super I/O */ +static void fdc37m81x_class_init(ObjectClass *klass, void *data) +{ + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + sc->serial.count = 2; /* NS16C550A */ + sc->parallel.count = 1; + sc->floppy.count = 1; /* SMSC 82077AA Compatible */ + sc->ide.count = 0; +} + +static const TypeInfo fdc37m81x_type_info = { + .name = TYPE_FDC37M81X_SUPERIO, + .parent = TYPE_ISA_SUPERIO, + .instance_size = sizeof(ISASuperIODevice), + .class_init = fdc37m81x_class_init, +}; + static void isa_superio_register_types(void) { type_register_static(&isa_superio_type_info); + type_register_static(&fdc37m81x_type_info); } type_init(isa_superio_register_types) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 9e0724ca5a..f6513a4fd5 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -27,14 +27,12 @@ #include "cpu.h" #include "hw/hw.h" #include "hw/i386/pc.h" +#include "hw/isa/superio.h" #include "hw/dma/i8257.h" #include "hw/char/serial.h" -#include "hw/char/parallel.h" -#include "hw/block/fdc.h" #include "net/net.h" #include "hw/boards.h" #include "hw/i2c/smbus.h" -#include "sysemu/block-backend.h" #include "hw/block/flash.h" #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" @@ -47,7 +45,6 @@ #include "hw/loader.h" #include "elf.h" #include "hw/timer/mc146818rtc.h" -#include "hw/input/i8042.h" #include "hw/timer/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" @@ -1005,10 +1002,8 @@ void mips_malta_init(MachineState *machine) qemu_irq cbus_irq, i8259_irq; int piix4_devfn; I2CBus *smbus; - int i; DriveInfo *dinfo; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; int fl_idx = 0; int fl_sectors = bios_size >> 16; int be; @@ -1023,15 +1018,6 @@ void mips_malta_init(MachineState *machine) qdev_init_nofail(dev); - /* Make sure the first 3 serial ports are associated with a device. */ - for(i = 0; i < 3; i++) { - if (!serial_hds[i]) { - char label[32]; - snprintf(label, sizeof(label), "serial%d", i); - serial_hds[i] = qemu_chr_new(label, "null"); - } - } - /* create CPU */ mips_create_cpu(s, machine->cpu_type, &cbus_irq, &i8259_irq); @@ -1067,7 +1053,14 @@ void mips_malta_init(MachineState *machine) #else be = 0; #endif + /* FPGA */ + + /* Make sure the second serial port is associated with a device. */ + if (!serial_hds[2]) { + serial_hds[2] = qemu_chr_new("fpga-uart", "null"); + } + /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hds[2]); @@ -1214,16 +1207,8 @@ void mips_malta_init(MachineState *machine) smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); g_free(smbus_eeprom_buf); - /* Super I/O */ - isa_create_simple(isa_bus, TYPE_I8042); - - serial_hds_isa_init(isa_bus, 0, 2); - parallel_hds_isa_init(isa_bus, 1); - - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - fdctrl_init_isa(isa_bus, fd); + /* Super I/O: SMS FDC37M817 */ + isa_create_simple(isa_bus, TYPE_FDC37M81X_SUPERIO); /* Network card */ network_init(pci_bus); diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index 3dd5448f8c..b47aac3cf8 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -54,4 +54,6 @@ typedef struct ISASuperIOClass { ISASuperIOFuncs ide; } ISASuperIOClass; +#define TYPE_FDC37M81X_SUPERIO "fdc37m81x-superio" + #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From 5c961c3fb11b19ac52385859ea03a10219892ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:38 +0100 Subject: hw/mips/mips_fulong2e: Factor out vt82c686b_southbridge_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-18-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/mips/mips_fulong2e.c | 83 ++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index a15d3b60cc..2697d772eb 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -77,8 +77,6 @@ #define FULONG2E_ATI_SLOT 6 #define FULONG2E_RTL8139_SLOT 7 -static ISADevice *pit; - static struct _loaderparams { int ram_size; const char *kernel_filename; @@ -231,11 +229,44 @@ static const uint8_t eeprom_spd[0x80] = { 0x20,0x30,0x20 }; -/* Audio support */ -static void audio_init (PCIBus *pci_bus) +static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, + I2CBus **i2c_bus, ISABus **p_isa_bus) { - vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5)); - vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6)); + qemu_irq *i8259; + ISABus *isa_bus; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + + isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(slot, 0)); + if (!isa_bus) { + fprintf(stderr, "vt82c686b_init error\n"); + exit(1); + } + *p_isa_bus = isa_bus; + /* Interrupt controller */ + /* The 8259 -> IP5 */ + i8259 = i8259_init(isa_bus, intc); + isa_bus_irqs(isa_bus, i8259); + /* init other devices */ + i8254_pit_init(isa_bus, 0x40, 0, NULL); + i8257_dma_init(isa_bus, 0); + + ide_drive_get(hd, ARRAY_SIZE(hd)); + vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(slot, 1)); + + pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci"); + pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci"); + + *i2c_bus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(slot, 4), 0xeee1, NULL); + + /* Audio support */ + vt82c686b_ac97_init(pci_bus, PCI_DEVFN(slot, 5)); + vt82c686b_mc97_init(pci_bus, PCI_DEVFN(slot, 6)); + + /* Super I/O */ + isa_create_simple(isa_bus, TYPE_I8042); + + serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); + parallel_hds_isa_init(isa_bus, 1); } /* Network support */ @@ -268,11 +299,9 @@ static void mips_fulong2e_init(MachineState *machine) MemoryRegion *bios = g_new(MemoryRegion, 1); long bios_size; int64_t kernel_entry; - qemu_irq *i8259; PCIBus *pci_bus; ISABus *isa_bus; I2CBus *smbus; - DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; MIPSCPU *cpu; CPUMIPSState *env; @@ -334,46 +363,16 @@ static void mips_fulong2e_init(MachineState *machine) /* North bridge, Bonito --> IP2 */ pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); - /* South bridge */ - ide_drive_get(hd, ARRAY_SIZE(hd)); - - isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); - if (!isa_bus) { - error_report("vt82c686b_init error"); - exit(1); - } - - /* Interrupt controller */ - /* The 8259 -> IP5 */ - i8259 = i8259_init(isa_bus, env->irq[5]); - isa_bus_irqs(isa_bus, i8259); - - vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1)); - pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2), - "vt82c686b-usb-uhci"); - pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3), - "vt82c686b-usb-uhci"); + /* South bridge -> IP5 */ + vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5], + &smbus, &isa_bus); - smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4), - 0xeee1, NULL); /* TODO: Populate SPD eeprom data. */ smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); - /* init other devices */ - pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); - i8257_dma_init(isa_bus, 0); - - /* Super I/O */ - isa_create_simple(isa_bus, TYPE_I8042); - mc146818_rtc_init(isa_bus, 2000, NULL); - serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); - parallel_hds_isa_init(isa_bus, 1); - - /* Sound card */ - audio_init(pci_bus); - /* Network card */ + /* Network card: RTL8139D */ network_init(pci_bus); } -- cgit v1.2.1 From 728d89100367a0000315fcb96dd251caa0e84bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:39 +0100 Subject: hw/isa/vt82c686: Rename vt82c686b_init() -> vt82c686b_isa_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function only initialize the ISA bus. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-19-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/vt82c686.c | 2 +- hw/mips/mips_fulong2e.c | 2 +- include/hw/isa/vt82c686.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 070cc1889f..7eaf3c7e8f 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -478,7 +478,7 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp) qemu_register_reset(vt82c686b_reset, d); } -ISABus *vt82c686b_init(PCIBus *bus, int devfn) +ISABus *vt82c686b_isa_init(PCIBus *bus, int devfn) { PCIDevice *d; diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 2697d772eb..b14dab8781 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -236,7 +236,7 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, ISABus *isa_bus; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(slot, 0)); + isa_bus = vt82c686b_isa_init(pci_bus, PCI_DEVFN(slot, 0)); if (!isa_bus) { fprintf(stderr, "vt82c686b_init error\n"); exit(1); diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index 471b5e9e53..db97c8ed7a 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -2,7 +2,7 @@ #define HW_VT82C686_H /* vt82c686.c */ -ISABus *vt82c686b_init(PCIBus * bus, int devfn); +ISABus *vt82c686b_isa_init(PCIBus * bus, int devfn); void vt82c686b_ac97_init(PCIBus *bus, int devfn); void vt82c686b_mc97_init(PCIBus *bus, int devfn); I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, -- cgit v1.2.1 From 98cf824b5f82b78ee1d6411b4e304a13f5f92502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:40 +0100 Subject: hw/isa/vt82c686: Add the TYPE_VT82C686B_SUPERIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-20-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/isa/vt82c686.c | 20 ++++++++++++++++++++ hw/mips/mips_fulong2e.c | 15 +++------------ include/hw/isa/vt82c686.h | 2 ++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 7eaf3c7e8f..cff1946232 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -17,6 +17,7 @@ #include "hw/i2c/smbus.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" +#include "hw/isa/superio.h" #include "hw/sysbus.h" #include "hw/mips/mips.h" #include "hw/isa/apm.h" @@ -519,11 +520,30 @@ static const TypeInfo via_info = { }, }; +static void vt82c686b_superio_class_init(ObjectClass *klass, void *data) +{ + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + sc->serial.count = 2; + sc->parallel.count = 1; + sc->ide.count = 0; + sc->floppy.count = 1; +} + +static const TypeInfo via_superio_info = { + .name = TYPE_VT82C686B_SUPERIO, + .parent = TYPE_ISA_SUPERIO, + .instance_size = sizeof(ISASuperIODevice), + .class_size = sizeof(ISASuperIOClass), + .class_init = vt82c686b_superio_class_init, +}; + static void vt82c686b_register_types(void) { type_register_static(&via_ac97_info); type_register_static(&via_mc97_info); type_register_static(&via_pm_info); + type_register_static(&via_superio_info); type_register_static(&via_info); } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index b14dab8781..02fb2fdcc4 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -23,9 +23,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/dma/i8257.h" -#include "hw/char/serial.h" -#include "hw/char/parallel.h" -#include "hw/block/fdc.h" +#include "hw/isa/superio.h" #include "net/net.h" #include "hw/boards.h" #include "hw/i2c/smbus.h" @@ -33,7 +31,6 @@ #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" -#include "sysemu/sysemu.h" #include "audio/audio.h" #include "qemu/log.h" #include "hw/loader.h" @@ -43,8 +40,6 @@ #include "hw/isa/vt82c686.h" #include "hw/timer/mc146818rtc.h" #include "hw/timer/i8254.h" -#include "hw/input/i8042.h" -#include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "qemu/error-report.h" @@ -249,6 +244,8 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, /* init other devices */ i8254_pit_init(isa_bus, 0x40, 0, NULL); i8257_dma_init(isa_bus, 0); + /* Super I/O */ + isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO); ide_drive_get(hd, ARRAY_SIZE(hd)); vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(slot, 1)); @@ -261,12 +258,6 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, /* Audio support */ vt82c686b_ac97_init(pci_bus, PCI_DEVFN(slot, 5)); vt82c686b_mc97_init(pci_bus, PCI_DEVFN(slot, 6)); - - /* Super I/O */ - isa_create_simple(isa_bus, TYPE_I8042); - - serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); - parallel_hds_isa_init(isa_bus, 1); } /* Network support */ diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index db97c8ed7a..c3c2b6e786 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -1,6 +1,8 @@ #ifndef HW_VT82C686_H #define HW_VT82C686_H +#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" + /* vt82c686.c */ ISABus *vt82c686b_isa_init(PCIBus * bus, int devfn); void vt82c686b_ac97_init(PCIBus *bus, int devfn); -- cgit v1.2.1 From 0170a3fcb3b8ed03fbf55e71b731c829137a3c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:41 +0100 Subject: MAINTAINERS: Add entries for the VT82C686B Super I/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far, it is only used by the MIPS Fulong 2E mini PC. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-21-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9f7b8e79c4..07684a1f2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -700,6 +700,8 @@ Fulong 2E M: Yongbok Kim S: Odd Fixes F: hw/mips/mips_fulong2e.c +F: hw/isa/vt82c686.c +F: include/hw/isa/vt82c686.h Boston M: Paul Burton -- cgit v1.2.1 From b250d04a3b39bec01f79d376777823870703f45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:42 +0100 Subject: MAINTAINERS: Split the Alpha TCG/machine section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-22-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 07684a1f2d..b17324107f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -127,7 +127,6 @@ Alpha M: Richard Henderson S: Maintained F: target/alpha/ -F: hw/alpha/ F: tests/tcg/alpha/ F: disas/alpha.c @@ -413,6 +412,11 @@ F: include/*/*win32* X: qga/*win32* F: qemu.nsi +Alpha Machines +M: Richard Henderson +S: Maintained +F: hw/alpha/ + ARM Machines ------------ Allwinner-a10 -- cgit v1.2.1 From 7bea0dd434e5cf5b26c28f06d4e2e912bf397b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:43 +0100 Subject: hw/isa/superio: Add the SMC FDC37C669 Super I/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-23-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + hw/isa/Makefile.objs | 2 +- hw/isa/smc37c669-superio.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/isa/superio.h | 1 + 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 hw/isa/smc37c669-superio.c diff --git a/MAINTAINERS b/MAINTAINERS index b17324107f..216d01efd6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -416,6 +416,7 @@ Alpha Machines M: Richard Henderson S: Maintained F: hw/alpha/ +F: hw/isa/smc37c669-superio.c ARM Machines ------------ diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index cac655ba58..83e06f6c04 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -1,5 +1,5 @@ common-obj-$(CONFIG_ISA_BUS) += isa-bus.o -common-obj-$(CONFIG_ISA_BUS) += isa-superio.o +common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o common-obj-$(CONFIG_PC87312) += pc87312.o diff --git a/hw/isa/smc37c669-superio.c b/hw/isa/smc37c669-superio.c new file mode 100644 index 0000000000..aa233c6967 --- /dev/null +++ b/hw/isa/smc37c669-superio.c @@ -0,0 +1,115 @@ +/* + * SMC FDC37C669 Super I/O controller + * + * Copyright (c) 2018 Philippe Mathieu-Daudé + * + * This code is licensed under the GNU GPLv2 and later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/isa/superio.h" + +/* UARTs (compatible with NS16450 or PC16550) */ + +static bool is_serial_enabled(ISASuperIODevice *sio, uint8_t index) +{ + return index < 2; +} + +static uint16_t get_serial_iobase(ISASuperIODevice *sio, uint8_t index) +{ + return index ? 0x2f8 : 0x3f8; +} + +static unsigned int get_serial_irq(ISASuperIODevice *sio, uint8_t index) +{ + return index ? 3 : 4; +} + +/* Parallel port */ + +static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index) +{ + return index < 1; +} + +static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index) +{ + return 0x3bc; +} + +static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index) +{ + return 7; +} + +static unsigned int get_parallel_dma(ISASuperIODevice *sio, uint8_t index) +{ + return 3; +} + +/* Diskette controller (Software compatible with the Intel PC8477) */ + +static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index) +{ + return index < 1; +} + +static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index) +{ + return 0x3f0; +} + +static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index) +{ + return 6; +} + +static unsigned int get_fdc_dma(ISASuperIODevice *sio, uint8_t index) +{ + return 2; +} + +static void smc37c669_class_init(ObjectClass *klass, void *data) +{ + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + sc->parallel = (ISASuperIOFuncs){ + .count = 1, + .is_enabled = is_parallel_enabled, + .get_iobase = get_parallel_iobase, + .get_irq = get_parallel_irq, + .get_dma = get_parallel_dma, + }; + sc->serial = (ISASuperIOFuncs){ + .count = 2, + .is_enabled = is_serial_enabled, + .get_iobase = get_serial_iobase, + .get_irq = get_serial_irq, + }; + sc->floppy = (ISASuperIOFuncs){ + .count = 1, + .is_enabled = is_fdc_enabled, + .get_iobase = get_fdc_iobase, + .get_irq = get_fdc_irq, + .get_dma = get_fdc_dma, + }; + sc->ide.count = 0; +} + +static const TypeInfo smc37c669_type_info = { + .name = TYPE_SMC37C669_SUPERIO, + .parent = TYPE_ISA_SUPERIO, + .instance_size = sizeof(ISASuperIODevice), + .class_size = sizeof(ISASuperIOClass), + .class_init = smc37c669_class_init, +}; + +static void smc37c669_register_types(void) +{ + type_register_static(&smc37c669_type_info); +} + +type_init(smc37c669_register_types) diff --git a/include/hw/isa/superio.h b/include/hw/isa/superio.h index b47aac3cf8..f9ba29aa30 100644 --- a/include/hw/isa/superio.h +++ b/include/hw/isa/superio.h @@ -55,5 +55,6 @@ typedef struct ISASuperIOClass { } ISASuperIOClass; #define TYPE_FDC37M81X_SUPERIO "fdc37m81x-superio" +#define TYPE_SMC37C669_SUPERIO "smc37c669-superio" #endif /* HW_ISA_SUPERIO_H */ -- cgit v1.2.1 From f4564fc0e8138bdc33c9783991f7173645a1396a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:44 +0100 Subject: hw/alpha/dp264: Add the ISA DMA controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-24-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- default-configs/alpha-softmmu.mak | 2 ++ hw/alpha/dp264.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak index e0d75e3058..3740adc5e9 100644 --- a/default-configs/alpha-softmmu.mak +++ b/default-configs/alpha-softmmu.mak @@ -4,7 +4,9 @@ include pci.mak include usb.mak CONFIG_SERIAL=y CONFIG_SERIAL_ISA=y +CONFIG_I82374=y CONFIG_I8254=y +CONFIG_I8257=y CONFIG_PCKBD=y CONFIG_VGA_CIRRUS=y CONFIG_IDE_CORE=y diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index e13cb576fd..ffad678ea7 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -21,6 +21,7 @@ #include "hw/timer/i8254.h" #include "hw/input/i8042.h" #include "hw/char/serial.h" +#include "hw/dma/i8257.h" #include "qemu/cutils.h" #define MAX_IDE_BUS 2 @@ -95,6 +96,9 @@ static void clipper_init(MachineState *machine) pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL); } + /* 2 82C37 (dma) */ + isa_create_simple(isa_bus, "i82374"); + /* IDE disk setup. */ { DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; -- cgit v1.2.1 From a4cb773928e047b137c6998209cf2eec857fac6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:45 +0100 Subject: hw/alpha/dp264: Use the TYPE_SMC37C669_SUPERIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-25-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- default-configs/alpha-softmmu.mak | 3 +++ hw/alpha/dp264.c | 10 ++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak index 3740adc5e9..bbe361f01a 100644 --- a/default-configs/alpha-softmmu.mak +++ b/default-configs/alpha-softmmu.mak @@ -7,6 +7,9 @@ CONFIG_SERIAL_ISA=y CONFIG_I82374=y CONFIG_I8254=y CONFIG_I8257=y +CONFIG_PARALLEL=y +CONFIG_PARALLEL_ISA=y +CONFIG_FDC=y CONFIG_PCKBD=y CONFIG_VGA_CIRRUS=y CONFIG_IDE_CORE=y diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index ffad678ea7..80b987f7fb 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -19,8 +19,7 @@ #include "hw/timer/mc146818rtc.h" #include "hw/ide.h" #include "hw/timer/i8254.h" -#include "hw/input/i8042.h" -#include "hw/char/serial.h" +#include "hw/isa/superio.h" #include "hw/dma/i8257.h" #include "qemu/cutils.h" @@ -83,14 +82,10 @@ static void clipper_init(MachineState *machine) mc146818_rtc_init(isa_bus, 1900, rtc_irq); i8254_pit_init(isa_bus, 0x40, 0, NULL); - isa_create_simple(isa_bus, TYPE_I8042); /* VGA setup. Don't bother loading the bios. */ pci_vga_init(pci_bus); - /* Serial code setup. */ - serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); - /* Network setup. e1000 is good enough, failing Tulip support. */ for (i = 0; i < nb_nics; i++) { pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL); @@ -99,6 +94,9 @@ static void clipper_init(MachineState *machine) /* 2 82C37 (dma) */ isa_create_simple(isa_bus, "i82374"); + /* Super I/O */ + isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO); + /* IDE disk setup. */ { DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; -- cgit v1.2.1 From ac64273c66ab136c44043259162a89ec89d21e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Mar 2018 23:39:46 +0100 Subject: hw/i386/pc: Factor out the superio code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20180308223946.26784-26-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 72 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 853a01d791..d36bac8c89 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1517,6 +1517,44 @@ static const MemoryRegionOps ioportF0_io_ops = { }, }; +static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) +{ + int i; + DriveInfo *fd[MAX_FD]; + qemu_irq *a20_line; + ISADevice *i8042, *port92, *vmmouse; + + serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); + parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); + + for (i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + create_fdctrl |= !!fd[i]; + } + if (create_fdctrl) { + fdctrl_init_isa(isa_bus, fd); + } + + i8042 = isa_create_simple(isa_bus, "i8042"); + if (!no_vmport) { + vmport_init(isa_bus); + vmmouse = isa_try_create(isa_bus, "vmmouse"); + } else { + vmmouse = NULL; + } + if (vmmouse) { + DeviceState *dev = DEVICE(vmmouse); + qdev_prop_set_ptr(dev, "ps2_mouse", i8042); + qdev_init_nofail(dev); + } + port92 = isa_create_simple(isa_bus, "port92"); + + a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); + i8042_setup_a20_line(i8042, a20_line[0]); + port92_init(port92, a20_line[1]); + g_free(a20_line); +} + void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, @@ -1525,13 +1563,11 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, uint32_t hpet_irqs) { int i; - DriveInfo *fd[MAX_FD]; DeviceState *hpet = NULL; int pit_isa_irq = 0; qemu_irq pit_alt_irq = NULL; qemu_irq rtc_irq = NULL; - qemu_irq *a20_line; - ISADevice *i8042, *port92, *vmmouse, *pit = NULL; + ISADevice *pit = NULL; MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); @@ -1588,36 +1624,10 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, pcspk_init(isa_bus, pit); } - serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); - parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); - - a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); - i8042 = isa_create_simple(isa_bus, "i8042"); - i8042_setup_a20_line(i8042, a20_line[0]); - if (!no_vmport) { - vmport_init(isa_bus); - vmmouse = isa_try_create(isa_bus, "vmmouse"); - } else { - vmmouse = NULL; - } - if (vmmouse) { - DeviceState *dev = DEVICE(vmmouse); - qdev_prop_set_ptr(dev, "ps2_mouse", i8042); - qdev_init_nofail(dev); - } - port92 = isa_create_simple(isa_bus, "port92"); - port92_init(port92, a20_line[1]); - g_free(a20_line); - i8257_dma_init(isa_bus, 0); - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - create_fdctrl |= !!fd[i]; - } - if (create_fdctrl) { - fdctrl_init_isa(isa_bus, fd); - } + /* Super I/O */ + pc_superio_init(isa_bus, create_fdctrl, no_vmport); } void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) -- cgit v1.2.1 From 5f3bdfd4fa33255542a4b6249913d9ffb11b44f9 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:51:41 +0300 Subject: cpu-exec: fix exception_index handling Function cpu_handle_interrupt calls cc->cpu_exec_interrupt to process pending hardware interrupts. Under the hood cpu_exec_interrupt uses cpu->exception_index to pass information to the internal function which is usually common for exception and interrupt processing. But this value is not reset after return and may be processed again by cpu_handle_exception. This does not happen due to overwriting the exception_index at the end of cpu_handle_interrupt. But this branch may also overwrite the valid exception_index in some cases. Therefore this patch: 1. resets exception_index just after the call to cpu_exec_interrupt 2. prevents overwriting the meaningful value of exception_index Signed-off-by: Pavel Dovgalyuk Signed-off-by: Paolo Bonzini Message-Id: <20180227095140.1060.61357.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- accel/tcg/cpu-exec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 280200f737..9cc697205c 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -585,6 +585,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, else { if (cc->cpu_exec_interrupt(cpu, interrupt_request)) { replay_interrupt(); + cpu->exception_index = -1; *last_tb = NULL; } /* The target hook may have updated the 'cpu->interrupt_request'; @@ -606,7 +607,9 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, if (unlikely(atomic_read(&cpu->exit_request) || (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) { atomic_set(&cpu->exit_request, 0); - cpu->exception_index = EXCP_INTERRUPT; + if (cpu->exception_index == -1) { + cpu->exception_index = EXCP_INTERRUPT; + } return true; } -- cgit v1.2.1 From 1a96e3c1e7dbb466a8c93743b8f5ae37cc023766 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:03 +0300 Subject: replay: fix processing async events Asynchronous events saved at checkpoints may invoke callbacks when processed. These callbacks may also generate/read new events (e.g. clock reads). Therefore event processing flag must be reset before callback invocation. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095203.1060.70831.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay-events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index 94a6dcccfc..768b505f3d 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -295,13 +295,13 @@ void replay_read_events(int checkpoint) if (!event) { break; } + replay_finish_event(); + read_event_kind = -1; replay_mutex_unlock(); replay_run_event(event); replay_mutex_lock(); g_free(event); - replay_finish_event(); - read_event_kind = -1; } } -- cgit v1.2.1 From 1652e0c30f28b755fde72d363634a586f133dc20 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:09 +0300 Subject: replay: fixed replay_enable_events This patch fixes assignment to internal events_enabled variable. Now it is set only in record/replay mode. This affects the behavior of the external functions that check this flag. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095209.1060.45884.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay-events.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index 768b505f3d..e858254074 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -67,7 +67,9 @@ static void replay_run_event(Event *event) void replay_enable_events(void) { - events_enabled = true; + if (replay_mode != REPLAY_MODE_NONE) { + events_enabled = true; + } } bool replay_has_events(void) @@ -141,7 +143,7 @@ void replay_add_event(ReplayAsyncEventKind event_kind, void replay_bh_schedule_event(QEMUBH *bh) { - if (replay_mode != REPLAY_MODE_NONE && events_enabled) { + if (events_enabled) { uint64_t id = replay_get_current_step(); replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); } else { @@ -161,7 +163,7 @@ void replay_add_input_sync_event(void) void replay_block_event(QEMUBH *bh, uint64_t id) { - if (replay_mode != REPLAY_MODE_NONE && events_enabled) { + if (events_enabled) { replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); } else { qemu_bh_schedule(bh); -- cgit v1.2.1 From 377b21ccea1755a8b0dae822c29567c58dda6939 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:14 +0300 Subject: replay: fix save/load vm for non-empty queue This patch does not allows saving/loading vmstate when replay events queue is not empty. There is no reliable way to save events queue, because it describes internal coroutine state. Therefore saving and loading operations should be deferred to another record/replay step. Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095214.1060.32939.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- include/sysemu/replay.h | 3 +++ migration/savevm.c | 13 +++++++++++++ replay/replay-snapshot.c | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index c0204e641c..401de12130 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -166,5 +166,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size); /*! Called at the start of execution. Loads or saves initial vmstate depending on execution mode. */ void replay_vmstate_init(void); +/*! Called to ensure that replay state is consistent and VM snapshot + can be created */ +bool replay_can_snapshot(void); #endif diff --git a/migration/savevm.c b/migration/savevm.c index 358c5b51e2..fbeac658c1 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -54,6 +54,7 @@ #include "qemu/cutils.h" #include "io/channel-buffer.h" #include "io/channel-file.h" +#include "sysemu/replay.h" #ifndef ETH_P_RARP #define ETH_P_RARP 0x8035 @@ -2197,6 +2198,12 @@ int save_snapshot(const char *name, Error **errp) struct tm tm; AioContext *aio_context; + if (!replay_can_snapshot()) { + error_report("Record/replay does not allow making snapshot " + "right now. Try once more later."); + return ret; + } + if (!bdrv_all_can_snapshot(&bs)) { error_setg(errp, "Device '%s' is writable but does not support " "snapshots", bdrv_get_device_name(bs)); @@ -2388,6 +2395,12 @@ int load_snapshot(const char *name, Error **errp) AioContext *aio_context; MigrationIncomingState *mis = migration_incoming_get_current(); + if (!replay_can_snapshot()) { + error_report("Record/replay does not allow loading snapshot " + "right now. Try once more later."); + return -EINVAL; + } + if (!bdrv_all_can_snapshot(&bs)) { error_setg(errp, "Device '%s' is writable but does not support snapshots", diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index b2e10769a6..7075986ab5 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -83,3 +83,9 @@ void replay_vmstate_init(void) } } } + +bool replay_can_snapshot(void) +{ + return replay_mode == REPLAY_MODE_NONE + || !replay_has_events(); +} -- cgit v1.2.1 From bb040e006f0245ca376b45dc5ea247f6e1f02648 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:20 +0300 Subject: replay: added replay log format description This patch adds description of the replay log file format into the docs/replay.txt. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095220.1060.58759.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- docs/replay.txt | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/replay.txt b/docs/replay.txt index 486c1e0e9d..c52407fe23 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -232,3 +232,72 @@ Audio devices Audio data is recorded and replay automatically. The command line for recording and replaying must contain identical specifications of audio hardware, e.g.: -soundhw ac97 + +Replay log format +----------------- + +Record/replay log consits of the header and the sequence of execution +events. The header includes 4-byte replay version id and 8-byte reserved +field. Version is updated every time replay log format changes to prevent +using replay log created by another build of qemu. + +The sequence of the events describes virtual machine state changes. +It includes all non-deterministic inputs of VM, synchronization marks and +instruction counts used to correctly inject inputs at replay. + +Synchronization marks (checkpoints) are used for synchronizing qemu threads +that perform operations with virtual hardware. These operations may change +system's state (e.g., change some register or generate interrupt) and +therefore should execute synchronously with CPU thread. + +Every event in the log includes 1-byte event id and optional arguments. +When argument is an array, it is stored as 4-byte array length +and corresponding number of bytes with data. +Here is the list of events that are written into the log: + + - EVENT_INSTRUCTION. Instructions executed since last event. + Argument: 4-byte number of executed instructions. + - EVENT_INTERRUPT. Used to synchronize interrupt processing. + - EVENT_EXCEPTION. Used to synchronize exception handling. + - EVENT_ASYNC. This is a group of events. They are always processed + together with checkpoints. When such an event is generated, it is + stored in the queue and processed only when checkpoint occurs. + Every such event is followed by 1-byte checkpoint id and 1-byte + async event id from the following list: + - REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes + callbacks that affect virtual machine state, but normally called + asyncronously. + Argument: 8-byte operation id. + - REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains + parameters of keyboard and mouse input operations + (key press/release, mouse pointer movement). + Arguments: 9-16 bytes depending of input event. + - REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event. + - REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input + initiated by the sender. + Arguments: 1-byte character device id. + Array with bytes were read. + - REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize + operations with disk and flash drives with CPU. + Argument: 8-byte operation id. + - REPLAY_ASYNC_EVENT_NET. Incoming network packet. + Arguments: 1-byte network adapter id. + 4-byte packet flags. + Array with packet bytes. + - EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu, + e.g., by closing the window. + - EVENT_CHAR_WRITE. Used to synchronize character output operations. + Arguments: 4-byte output function return value. + 4-byte offset in the output array. + - EVENT_CHAR_READ_ALL. Used to synchronize character input operations, + initiated by qemu. + Argument: Array with bytes that were read. + - EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation, + initiated by qemu. + Argument: 4-byte error code. + - EVENT_CLOCK + clock_id. Group of events for host clock read operations. + Argument: 8-byte clock value. + - EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of + CPU, internal threads, and asynchronous input events. May be followed + by one or more EVENT_ASYNC events. + - EVENT_END. Last event in the log. -- cgit v1.2.1 From 4b930d264cea0d72e775a7a57a8fce79158e8c10 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:26 +0300 Subject: replay: save prior value of the host clock This patch adds saving/restoring of the host clock field 'last'. It is used in host clock calculation and therefore clock may become incorrect when using restored vmstate. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095226.1060.50975.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- include/qemu/timer.h | 14 ++++++++++++++ replay/replay-internal.h | 2 ++ replay/replay-snapshot.c | 3 +++ util/qemu-timer.c | 12 ++++++++++++ 4 files changed, 31 insertions(+) diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 3b5a54b014..39ea907e65 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -251,6 +251,20 @@ bool qemu_clock_run_timers(QEMUClockType type); */ bool qemu_clock_run_all_timers(void); +/** + * qemu_clock_get_last: + * + * Returns last clock query time. + */ +uint64_t qemu_clock_get_last(QEMUClockType type); +/** + * qemu_clock_set_last: + * + * Sets last clock query time. + */ +void qemu_clock_set_last(QEMUClockType type, uint64_t last); + + /* * QEMUTimerList */ diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 3ebb19912a..be96d7e879 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -78,6 +78,8 @@ typedef struct ReplayState { This counter is global, because requests from different block devices should not get overlapping ids. */ uint64_t block_request_id; + /*! Prior value of the host clock */ + uint64_t host_clock_last; } ReplayState; extern ReplayState replay_state; diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index 7075986ab5..e0b2204765 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -25,6 +25,7 @@ static int replay_pre_save(void *opaque) { ReplayState *state = opaque; state->file_offset = ftell(replay_file); + state->host_clock_last = qemu_clock_get_last(QEMU_CLOCK_HOST); return 0; } @@ -33,6 +34,7 @@ static int replay_post_load(void *opaque, int version_id) { ReplayState *state = opaque; fseek(replay_file, state->file_offset, SEEK_SET); + qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last); /* If this was a vmstate, saved in recording mode, we need to initialize replay data fields. */ replay_fetch_data_kind(); @@ -54,6 +56,7 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), + VMSTATE_UINT64(host_clock_last, ReplayState), VMSTATE_END_OF_LIST() }, }; diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 82d56507a2..2ed1bf2778 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -622,6 +622,18 @@ int64_t qemu_clock_get_ns(QEMUClockType type) } } +uint64_t qemu_clock_get_last(QEMUClockType type) +{ + QEMUClock *clock = qemu_clock_ptr(type); + return clock->last; +} + +void qemu_clock_set_last(QEMUClockType type, uint64_t last) +{ + QEMUClock *clock = qemu_clock_ptr(type); + clock->last = last; +} + void qemu_clock_register_reset_notifier(QEMUClockType type, Notifier *notifier) { -- cgit v1.2.1 From 80be169c1fd178ed18d17012b7cdc09850ea8cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 27 Feb 2018 12:52:31 +0300 Subject: replay/replay.c: bump REPLAY_VERSION again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This time commit 802f045a5f61b781df55e4492d896b4d20503ba7 broke the replay file format. Also add a comment about this to replay-internal.h. Signed-off-by: Alex Bennée Reviewed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095231.1060.91180.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- replay/replay-internal.h | 2 +- replay/replay.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/replay/replay-internal.h b/replay/replay-internal.h index be96d7e879..8e4c701751 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -12,7 +12,7 @@ * */ - +/* Any changes to order/number of events will need to bump REPLAY_VERSION */ enum ReplayEvents { /* for instruction event */ EVENT_INSTRUCTION, diff --git a/replay/replay.c b/replay/replay.c index 7a23c62d61..9cddb6bfc9 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe02006 +#define REPLAY_VERSION 0xe02007 /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) -- cgit v1.2.1 From 180d30bebeff8e3687b50bd55d44e6a5a83bc4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 27 Feb 2018 12:52:37 +0300 Subject: replay/replay-internal.c: track holding of replay_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is modelled after the iothread mutex lock. We keep a TLS flag to indicate when that thread has acquired the lock and assert we don't double-lock or release when we shouldn't have. Signed-off-by: Alex Bennée Tested-by: Pavel Dovgalyuk Message-Id: <20180227095237.1060.44661.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- replay/replay-internal.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/replay/replay-internal.c b/replay/replay-internal.c index fca8514012..0d7e1d6bc4 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -169,6 +169,8 @@ void replay_finish_event(void) replay_fetch_data_kind(); } +static __thread bool replay_locked; + void replay_mutex_init(void) { qemu_mutex_init(&lock); @@ -179,13 +181,22 @@ void replay_mutex_destroy(void) qemu_mutex_destroy(&lock); } +static bool replay_mutex_locked(void) +{ + return replay_locked; +} + void replay_mutex_lock(void) { + g_assert(!replay_mutex_locked()); qemu_mutex_lock(&lock); + replay_locked = true; } void replay_mutex_unlock(void) { + g_assert(replay_mutex_locked()); + replay_locked = false; qemu_mutex_unlock(&lock); } -- cgit v1.2.1 From a36544d34c8b7e483386d29f9716ca9f4caad9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 27 Feb 2018 12:52:42 +0300 Subject: replay: make locking visible outside replay code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The replay_mutex_lock/unlock/locked functions are now going to be used for ensuring lock-step behaviour between the two threads. Make them public API functions and also provide stubs for non-QEMU builds on common paths. Signed-off-by: Alex Bennée Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095242.1060.16601.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- include/sysemu/replay.h | 13 +++++++++++++ replay/replay-internal.c | 2 +- replay/replay-internal.h | 6 +++--- stubs/replay.c | 8 ++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 401de12130..3ced6bc231 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -48,6 +48,19 @@ extern ReplayMode replay_mode; /* Name of the initial VM snapshot */ extern char *replay_snapshot; +/* Replay locking + * + * The locks are needed to protect the shared structures and log file + * when doing record/replay. They also are the main sync-point between + * the main-loop thread and the vCPU thread. This was a role + * previously filled by the BQL which has been busy trying to reduce + * its impact across the code. This ensures blocks of events stay + * sequential and reproducible. + */ + +void replay_mutex_lock(void); +void replay_mutex_unlock(void); + /* Replay process control functions */ /*! Enables recording or saving event log with specified parameters */ diff --git a/replay/replay-internal.c b/replay/replay-internal.c index 0d7e1d6bc4..7cdefeaa04 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -181,7 +181,7 @@ void replay_mutex_destroy(void) qemu_mutex_destroy(&lock); } -static bool replay_mutex_locked(void) +bool replay_mutex_locked(void) { return replay_locked; } diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 8e4c701751..41eee66e9b 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -100,12 +100,12 @@ int64_t replay_get_qword(void); void replay_get_array(uint8_t *buf, size_t *size); void replay_get_array_alloc(uint8_t **buf, size_t *size); -/* Mutex functions for protecting replay log file */ +/* Mutex functions for protecting replay log file and ensuring + * synchronisation between vCPU and main-loop threads. */ void replay_mutex_init(void); void replay_mutex_destroy(void); -void replay_mutex_lock(void); -void replay_mutex_unlock(void); +bool replay_mutex_locked(void); /*! Checks error status of the file. */ void replay_check_error(void); diff --git a/stubs/replay.c b/stubs/replay.c index 9c8aa48c9c..04279abb2c 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -72,3 +72,11 @@ uint64_t blkreplay_next_id(void) { return 0; } + +void replay_mutex_lock(void) +{ +} + +void replay_mutex_unlock(void) +{ +} -- cgit v1.2.1 From 1a423896fa4fc2ea49c64e7a493d88a8b251950d Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:54 +0300 Subject: replay: don't destroy mutex at exit Replay mutex is held by vCPU thread and destroy function is called from atexit of the main thread. Therefore we cannot destroy it safely. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Message-Id: <20180227095254.1060.96971.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay-internal.c | 5 ----- replay/replay-internal.h | 1 - replay/replay.c | 1 - 3 files changed, 7 deletions(-) diff --git a/replay/replay-internal.c b/replay/replay-internal.c index 7cdefeaa04..fa7bba6dfd 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -176,11 +176,6 @@ void replay_mutex_init(void) qemu_mutex_init(&lock); } -void replay_mutex_destroy(void) -{ - qemu_mutex_destroy(&lock); -} - bool replay_mutex_locked(void) { return replay_locked; diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 41eee66e9b..d4037058e4 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -104,7 +104,6 @@ void replay_get_array_alloc(uint8_t **buf, size_t *size); * synchronisation between vCPU and main-loop threads. */ void replay_mutex_init(void); -void replay_mutex_destroy(void); bool replay_mutex_locked(void); /*! Checks error status of the file. */ diff --git a/replay/replay.c b/replay/replay.c index 9cddb6bfc9..5d05ee0460 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -358,7 +358,6 @@ void replay_finish(void) replay_snapshot = NULL; replay_finish_events(); - replay_mutex_destroy(); } void replay_add_blocker(Error *reason) -- cgit v1.2.1 From d759c951f3287fad04210a52f2dc93f94cf58c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 27 Feb 2018 12:52:48 +0300 Subject: replay: push replay_mutex_lock up the call tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now instead of using the replay_lock to guard the output of the log we now use it to protect the whole execution section. This replaces what the BQL used to do when it was held during TCG execution. We also introduce some rules for locking order - mainly that you cannot take the replay_mutex while holding the BQL. This leads to some slight sophistry during start-up and extending the replay_mutex_destroy function to unlock the mutex without checking for the BQL condition so it can be cleanly dropped in the non-replay case. Signed-off-by: Alex Bennée Signed-off-by: Pavel Dovgalyuk Tested-by: Pavel Dovgalyuk Message-Id: <20180227095248.1060.40374.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Alex Bennée --- cpus.c | 24 ++++++++++++++++++++++-- docs/replay.txt | 22 ++++++++++++++++++++++ replay/replay-audio.c | 14 ++++---------- replay/replay-char.c | 21 ++++++++------------- replay/replay-events.c | 20 +++++++------------- replay/replay-internal.c | 24 ++++++++++++++++-------- replay/replay-time.c | 10 +++++----- replay/replay.c | 34 +++++++++++++--------------------- util/main-loop.c | 15 +++++++++++---- vl.c | 1 + 10 files changed, 109 insertions(+), 76 deletions(-) diff --git a/cpus.c b/cpus.c index c652da84cf..2e6701795b 100644 --- a/cpus.c +++ b/cpus.c @@ -1317,6 +1317,8 @@ static void prepare_icount_for_run(CPUState *cpu) insns_left = MIN(0xffff, cpu->icount_budget); cpu->icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; + + replay_mutex_lock(); } } @@ -1332,6 +1334,8 @@ static void process_icount_data(CPUState *cpu) cpu->icount_budget = 0; replay_account_executed_instructions(); + + replay_mutex_unlock(); } } @@ -1346,11 +1350,9 @@ static int tcg_cpu_exec(CPUState *cpu) #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif - qemu_mutex_unlock_iothread(); cpu_exec_start(cpu); ret = cpu_exec(cpu); cpu_exec_end(cpu); - qemu_mutex_lock_iothread(); #ifdef CONFIG_PROFILER tcg_time += profile_getclock() - ti; #endif @@ -1417,6 +1419,9 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) cpu->exit_request = 1; while (1) { + qemu_mutex_unlock_iothread(); + replay_mutex_lock(); + qemu_mutex_lock_iothread(); /* Account partial waits to QEMU_CLOCK_VIRTUAL. */ qemu_account_warp_timer(); @@ -1425,6 +1430,8 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) */ handle_icount_deadline(); + replay_mutex_unlock(); + if (!cpu) { cpu = first_cpu; } @@ -1440,11 +1447,13 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) if (cpu_can_run(cpu)) { int r; + qemu_mutex_unlock_iothread(); prepare_icount_for_run(cpu); r = tcg_cpu_exec(cpu); process_icount_data(cpu); + qemu_mutex_lock_iothread(); if (r == EXCP_DEBUG) { cpu_handle_guest_debug(cpu); @@ -1634,7 +1643,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { if (cpu_can_run(cpu)) { int r; + qemu_mutex_unlock_iothread(); r = tcg_cpu_exec(cpu); + qemu_mutex_lock_iothread(); switch (r) { case EXCP_DEBUG: cpu_handle_guest_debug(cpu); @@ -1781,12 +1792,21 @@ void pause_all_vcpus(void) } } + /* We need to drop the replay_lock so any vCPU threads woken up + * can finish their replay tasks + */ + replay_mutex_unlock(); + while (!all_vcpus_paused()) { qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex); CPU_FOREACH(cpu) { qemu_cpu_kick(cpu); } } + + qemu_mutex_unlock_iothread(); + replay_mutex_lock(); + qemu_mutex_lock_iothread(); } void cpu_resume(CPUState *cpu) diff --git a/docs/replay.txt b/docs/replay.txt index c52407fe23..959633e7ea 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -49,6 +49,28 @@ Modifications of qemu include: * recording/replaying user input (mouse and keyboard) * adding internal checkpoints for cpu and io synchronization +Locking and thread synchronisation +---------------------------------- + +Previously the synchronisation of the main thread and the vCPU thread +was ensured by the holding of the BQL. However the trend has been to +reduce the time the BQL was held across the system including under TCG +system emulation. As it is important that batches of events are kept +in sequence (e.g. expiring timers and checkpoints in the main thread +while instruction checkpoints are written by the vCPU thread) we need +another lock to keep things in lock-step. This role is now handled by +the replay_mutex_lock. It used to be held only for each event being +written but now it is held for a whole execution period. This results +in a deterministic ping-pong between the two main threads. + +As the BQL is now a finer grained lock than the replay_lock it is almost +certainly a bug, and a source of deadlocks, to take the +replay_mutex_lock while the BQL is held. This is enforced by an assert. +While the unlocks are usually in the reverse order, this is not +necessary; you can drop the replay_lock while holding the BQL, without +doing a more complicated unlock_iothread/replay_unlock/lock_iothread +sequence. + Non-deterministic events ------------------------ diff --git a/replay/replay-audio.c b/replay/replay-audio.c index 3d837434d4..b113836de4 100644 --- a/replay/replay-audio.c +++ b/replay/replay-audio.c @@ -19,20 +19,17 @@ void replay_audio_out(int *played) { if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_AUDIO_OUT); replay_put_dword(*played); - replay_mutex_unlock(); } else if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); replay_account_executed_instructions(); - replay_mutex_lock(); if (replay_next_event_is(EVENT_AUDIO_OUT)) { *played = replay_get_dword(); replay_finish_event(); - replay_mutex_unlock(); } else { - replay_mutex_unlock(); error_report("Missing audio out event in the replay log"); abort(); } @@ -44,8 +41,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size) int pos; uint64_t left, right; if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_AUDIO_IN); replay_put_dword(*recorded); replay_put_dword(*wpos); @@ -55,10 +52,9 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size) replay_put_qword(left); replay_put_qword(right); } - replay_mutex_unlock(); } else if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); replay_account_executed_instructions(); - replay_mutex_lock(); if (replay_next_event_is(EVENT_AUDIO_IN)) { *recorded = replay_get_dword(); *wpos = replay_get_dword(); @@ -69,9 +65,7 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size) audio_sample_from_uint64(samples, pos, left, right); } replay_finish_event(); - replay_mutex_unlock(); } else { - replay_mutex_unlock(); error_report("Missing audio in event in the replay log"); abort(); } diff --git a/replay/replay-char.c b/replay/replay-char.c index cbf7c04a9f..736cc8c2e6 100755 --- a/replay/replay-char.c +++ b/replay/replay-char.c @@ -96,25 +96,24 @@ void *replay_event_char_read_load(void) void replay_char_write_event_save(int res, int offset) { + g_assert(replay_mutex_locked()); + replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_CHAR_WRITE); replay_put_dword(res); replay_put_dword(offset); - replay_mutex_unlock(); } void replay_char_write_event_load(int *res, int *offset) { + g_assert(replay_mutex_locked()); + replay_account_executed_instructions(); - replay_mutex_lock(); if (replay_next_event_is(EVENT_CHAR_WRITE)) { *res = replay_get_dword(); *offset = replay_get_dword(); replay_finish_event(); - replay_mutex_unlock(); } else { - replay_mutex_unlock(); error_report("Missing character write event in the replay log"); exit(1); } @@ -122,23 +121,21 @@ void replay_char_write_event_load(int *res, int *offset) int replay_char_read_all_load(uint8_t *buf) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); + if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { size_t size; int res; replay_get_array(buf, &size); replay_finish_event(); - replay_mutex_unlock(); res = (int)size; assert(res >= 0); return res; } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { int res = replay_get_dword(); replay_finish_event(); - replay_mutex_unlock(); return res; } else { - replay_mutex_unlock(); error_report("Missing character read all event in the replay log"); exit(1); } @@ -146,19 +143,17 @@ int replay_char_read_all_load(uint8_t *buf) void replay_char_read_all_save_error(int res) { + g_assert(replay_mutex_locked()); assert(res < 0); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_CHAR_READ_ALL_ERROR); replay_put_dword(res); - replay_mutex_unlock(); } void replay_char_read_all_save_buf(uint8_t *buf, int offset) { + g_assert(replay_mutex_locked()); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_CHAR_READ_ALL); replay_put_array(buf, offset); - replay_mutex_unlock(); } diff --git a/replay/replay-events.c b/replay/replay-events.c index e858254074..54dd9d2606 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -79,16 +79,14 @@ bool replay_has_events(void) void replay_flush_events(void) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); + while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); - replay_mutex_unlock(); replay_run_event(event); - replay_mutex_lock(); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } - replay_mutex_unlock(); } void replay_disable_events(void) @@ -102,14 +100,14 @@ void replay_disable_events(void) void replay_clear_events(void) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); + while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } - replay_mutex_unlock(); } /*! Adds specified async event to the queue */ @@ -136,9 +134,8 @@ void replay_add_event(ReplayAsyncEventKind event_kind, event->opaque2 = opaque2; event->id = id; - replay_mutex_lock(); + g_assert(replay_mutex_locked()); QTAILQ_INSERT_TAIL(&events_list, event, events); - replay_mutex_unlock(); } void replay_bh_schedule_event(QEMUBH *bh) @@ -207,13 +204,11 @@ static void replay_save_event(Event *event, int checkpoint) /* Called with replay mutex locked */ void replay_save_events(int checkpoint) { + g_assert(replay_mutex_locked()); while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); replay_save_event(event, checkpoint); - - replay_mutex_unlock(); replay_run_event(event); - replay_mutex_lock(); QTAILQ_REMOVE(&events_list, event, events); g_free(event); } @@ -292,6 +287,7 @@ static Event *replay_read_event(int checkpoint) /* Called with replay mutex locked */ void replay_read_events(int checkpoint) { + g_assert(replay_mutex_locked()); while (replay_state.data_kind == EVENT_ASYNC) { Event *event = replay_read_event(checkpoint); if (!event) { @@ -299,9 +295,7 @@ void replay_read_events(int checkpoint) } replay_finish_event(); read_event_kind = -1; - replay_mutex_unlock(); replay_run_event(event); - replay_mutex_lock(); g_free(event); } diff --git a/replay/replay-internal.c b/replay/replay-internal.c index fa7bba6dfd..8e7474f787 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -174,6 +174,9 @@ static __thread bool replay_locked; void replay_mutex_init(void) { qemu_mutex_init(&lock); + /* Hold the mutex while we start-up */ + qemu_mutex_lock(&lock); + replay_locked = true; } bool replay_mutex_locked(void) @@ -181,25 +184,31 @@ bool replay_mutex_locked(void) return replay_locked; } +/* Ordering constraints, replay_lock must be taken before BQL */ void replay_mutex_lock(void) { - g_assert(!replay_mutex_locked()); - qemu_mutex_lock(&lock); - replay_locked = true; + if (replay_mode != REPLAY_MODE_NONE) { + g_assert(!qemu_mutex_iothread_locked()); + g_assert(!replay_mutex_locked()); + qemu_mutex_lock(&lock); + replay_locked = true; + } } void replay_mutex_unlock(void) { - g_assert(replay_mutex_locked()); - replay_locked = false; - qemu_mutex_unlock(&lock); + if (replay_mode != REPLAY_MODE_NONE) { + g_assert(replay_mutex_locked()); + replay_locked = false; + qemu_mutex_unlock(&lock); + } } /*! Saves cached instructions. */ void replay_save_instructions(void) { if (replay_file && replay_mode == REPLAY_MODE_RECORD) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); int diff = (int)(replay_get_current_step() - replay_state.current_step); /* Time can only go forward */ @@ -210,6 +219,5 @@ void replay_save_instructions(void) replay_put_dword(diff); replay_state.current_step += diff; } - replay_mutex_unlock(); } } diff --git a/replay/replay-time.c b/replay/replay-time.c index f70382a88f..6a7565ec8d 100644 --- a/replay/replay-time.c +++ b/replay/replay-time.c @@ -17,13 +17,13 @@ int64_t replay_save_clock(ReplayClockKind kind, int64_t clock) { - replay_save_instructions(); if (replay_file) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); + + replay_save_instructions(); replay_put_event(EVENT_CLOCK + kind); replay_put_qword(clock); - replay_mutex_unlock(); } return clock; @@ -46,16 +46,16 @@ void replay_read_next_clock(ReplayClockKind kind) /*! Reads next clock event from the input. */ int64_t replay_read_clock(ReplayClockKind kind) { + g_assert(replay_file && replay_mutex_locked()); + replay_account_executed_instructions(); if (replay_file) { int64_t ret; - replay_mutex_lock(); if (replay_next_event_is(EVENT_CLOCK + kind)) { replay_read_next_clock(kind); } ret = replay_state.cached_clock[kind]; - replay_mutex_unlock(); return ret; } diff --git a/replay/replay.c b/replay/replay.c index 5d05ee0460..90f98b7490 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -81,7 +81,7 @@ int replay_get_instructions(void) void replay_account_executed_instructions(void) { if (replay_mode == REPLAY_MODE_PLAY) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); if (replay_state.instructions_count > 0) { int count = (int)(replay_get_current_step() - replay_state.current_step); @@ -100,24 +100,22 @@ void replay_account_executed_instructions(void) qemu_notify_event(); } } - replay_mutex_unlock(); } } bool replay_exception(void) { + if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_EXCEPTION); - replay_mutex_unlock(); return true; } else if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); bool res = replay_has_exception(); if (res) { - replay_mutex_lock(); replay_finish_event(); - replay_mutex_unlock(); } return res; } @@ -129,10 +127,9 @@ bool replay_has_exception(void) { bool res = false; if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); replay_account_executed_instructions(); - replay_mutex_lock(); res = replay_next_event_is(EVENT_EXCEPTION); - replay_mutex_unlock(); } return res; @@ -141,17 +138,15 @@ bool replay_has_exception(void) bool replay_interrupt(void) { if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); replay_save_instructions(); - replay_mutex_lock(); replay_put_event(EVENT_INTERRUPT); - replay_mutex_unlock(); return true; } else if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); bool res = replay_has_interrupt(); if (res) { - replay_mutex_lock(); replay_finish_event(); - replay_mutex_unlock(); } return res; } @@ -163,10 +158,9 @@ bool replay_has_interrupt(void) { bool res = false; if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); replay_account_executed_instructions(); - replay_mutex_lock(); res = replay_next_event_is(EVENT_INTERRUPT); - replay_mutex_unlock(); } return res; } @@ -174,9 +168,8 @@ bool replay_has_interrupt(void) void replay_shutdown_request(ShutdownCause cause) { if (replay_mode == REPLAY_MODE_RECORD) { - replay_mutex_lock(); + g_assert(replay_mutex_locked()); replay_put_event(EVENT_SHUTDOWN + cause); - replay_mutex_unlock(); } } @@ -190,9 +183,9 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) return true; } - replay_mutex_lock(); if (replay_mode == REPLAY_MODE_PLAY) { + g_assert(replay_mutex_locked()); if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { replay_finish_event(); } else if (replay_state.data_kind != EVENT_ASYNC) { @@ -205,12 +198,12 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) checkpoint were processed */ res = replay_state.data_kind != EVENT_ASYNC; } else if (replay_mode == REPLAY_MODE_RECORD) { + g_assert(replay_mutex_locked()); replay_put_event(EVENT_CHECKPOINT + checkpoint); replay_save_events(checkpoint); res = true; } out: - replay_mutex_unlock(); return res; } @@ -233,8 +226,6 @@ static void replay_enable(const char *fname, int mode) atexit(replay_finish); - replay_mutex_init(); - replay_file = fopen(fname, fmode); if (replay_file == NULL) { fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); @@ -242,8 +233,9 @@ static void replay_enable(const char *fname, int mode) } replay_filename = g_strdup(fname); - replay_mode = mode; + replay_mutex_init(); + replay_state.data_kind = -1; replay_state.instructions_count = 0; replay_state.current_step = 0; diff --git a/util/main-loop.c b/util/main-loop.c index 7558eb5f53..992f9b0f34 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -29,6 +29,7 @@ #include "qemu/sockets.h" // struct in_addr needed for libslirp.h #include "sysemu/qtest.h" #include "sysemu/cpus.h" +#include "sysemu/replay.h" #include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" @@ -245,18 +246,19 @@ static int os_host_main_loop_wait(int64_t timeout) timeout = SCALE_MS; } + if (timeout) { spin_counter = 0; - qemu_mutex_unlock_iothread(); } else { spin_counter++; } + qemu_mutex_unlock_iothread(); + replay_mutex_unlock(); ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout); - if (timeout) { - qemu_mutex_lock_iothread(); - } + replay_mutex_lock(); + qemu_mutex_lock_iothread(); glib_pollfds_poll(); @@ -463,8 +465,13 @@ static int os_host_main_loop_wait(int64_t timeout) poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout); qemu_mutex_unlock_iothread(); + + replay_mutex_unlock(); + g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns); + replay_mutex_lock(); + qemu_mutex_lock_iothread(); if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { diff --git a/vl.c b/vl.c index e81152417a..5925a4b502 100644 --- a/vl.c +++ b/vl.c @@ -3058,6 +3058,7 @@ int main(int argc, char **argv, char **envp) qemu_init_cpu_list(); qemu_init_cpu_loop(); + qemu_mutex_lock_iothread(); atexit(qemu_run_exit_notifiers); -- cgit v1.2.1 From 6dc0f5296359ff59c248215a965c8658dea9544b Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:52:59 +0300 Subject: replay: check return values of fwrite This patch adds error reporting when fwrite cannot completely save the buffer to the file. Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095259.1060.86410.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay-internal.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/replay/replay-internal.c b/replay/replay-internal.c index 8e7474f787..b077cb5fd5 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -24,12 +24,23 @@ static QemuMutex lock; /* File for replay writing */ +static bool write_error; FILE *replay_file; +static void replay_write_error(void) +{ + if (!write_error) { + error_report("replay write error"); + write_error = true; + } +} + void replay_put_byte(uint8_t byte) { if (replay_file) { - putc(byte, replay_file); + if (putc(byte, replay_file) == EOF) { + replay_write_error(); + } } } @@ -62,7 +73,9 @@ void replay_put_array(const uint8_t *buf, size_t size) { if (replay_file) { replay_put_dword(size); - fwrite(buf, 1, size, replay_file); + if (fwrite(buf, 1, size, replay_file) != size) { + replay_write_error(); + } } } -- cgit v1.2.1 From 66eb7825d0bd84a870a054fb208fe765317109fa Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:53:05 +0300 Subject: replay: avoid recursive call of checkpoints This patch adds a flag which denies recursive call of replay_checkpoint function. Checkpoints may be accompanied by the hardware events. When event is processed, virtual device may invoke timer modification functions that also invoke the checkpoint function. This leads to infinite loop. Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095305.1060.56463.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/replay/replay.c b/replay/replay.c index 90f98b7490..eae8daf18a 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -176,13 +176,24 @@ void replay_shutdown_request(ShutdownCause cause) bool replay_checkpoint(ReplayCheckpoint checkpoint) { bool res = false; + static bool in_checkpoint; assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); - replay_save_instructions(); if (!replay_file) { return true; } + if (in_checkpoint) { + /* If we are already in checkpoint, then there is no need + for additional synchronization. + Recursion occurs when HW event modifies timers. + Timer modification may invoke the checkpoint and + proceed to recursion. */ + return true; + } + in_checkpoint = true; + + replay_save_instructions(); if (replay_mode == REPLAY_MODE_PLAY) { g_assert(replay_mutex_locked()); @@ -204,6 +215,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) res = true; } out: + in_checkpoint = false; return res; } -- cgit v1.2.1 From 821c113033075d4f1b50966d92022a1064085422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 27 Feb 2018 12:53:10 +0300 Subject: scripts/replay-dump.py: replay log dumper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This script is a debugging tool for looking through the contents of a replay log file. It is incomplete but should fail gracefully at events it doesn't understand. It currently understands two different log formats as the audio record/replay support was merged during since MTTCG. It was written to help debug what has caused the BQL changes to break replay support. Signed-off-by: Alex Bennée Message-Id: <20180227095310.1060.14500.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- scripts/replay-dump.py | 308 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100755 scripts/replay-dump.py diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py new file mode 100755 index 0000000000..e274086277 --- /dev/null +++ b/scripts/replay-dump.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Dump the contents of a recorded execution stream +# +# Copyright (c) 2017 Alex Bennée +# +# 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 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 . + +import argparse +import struct +from collections import namedtuple + +# This mirrors some of the global replay state which some of the +# stream loading refers to. Some decoders may read the next event so +# we need handle that case. Calling reuse_event will ensure the next +# event is read from the cache rather than advancing the file. + +class ReplayState(object): + def __init__(self): + self.event = -1 + self.event_count = 0 + self.already_read = False + self.current_checkpoint = 0 + self.checkpoint = 0 + + def set_event(self, ev): + self.event = ev + self.event_count += 1 + + def get_event(self): + self.already_read = False + return self.event + + def reuse_event(self, ev): + self.event = ev + self.already_read = True + + def set_checkpoint(self): + self.checkpoint = self.event - self.checkpoint_start + + def get_checkpoint(self): + return self.checkpoint + +replay_state = ReplayState() + +# Simple read functions that mirror replay-internal.c +# The file-stream is big-endian and manually written out a byte at a time. + +def read_byte(fin): + "Read a single byte" + return struct.unpack('>B', fin.read(1))[0] + +def read_event(fin): + "Read a single byte event, but save some state" + if replay_state.already_read: + return replay_state.get_event() + else: + replay_state.set_event(read_byte(fin)) + return replay_state.event + +def read_word(fin): + "Read a 16 bit word" + return struct.unpack('>H', fin.read(2))[0] + +def read_dword(fin): + "Read a 32 bit word" + return struct.unpack('>I', fin.read(4))[0] + +def read_qword(fin): + "Read a 64 bit word" + return struct.unpack('>Q', fin.read(8))[0] + +# Generic decoder structure +Decoder = namedtuple("Decoder", "eid name fn") + +def call_decode(table, index, dumpfile): + "Search decode table for next step" + decoder = next((d for d in table if d.eid == index), None) + if not decoder: + print "Could not decode index: %d" % (index) + print "Entry is: %s" % (decoder) + print "Decode Table is:\n%s" % (table) + return False + else: + return decoder.fn(decoder.eid, decoder.name, dumpfile) + +# Print event +def print_event(eid, name, string=None, event_count=None): + "Print event with count" + if not event_count: + event_count = replay_state.event_count + + if string: + print "%d:%s(%d) %s" % (event_count, name, eid, string) + else: + print "%d:%s(%d)" % (event_count, name, eid) + + +# Decoders for each event type + +def decode_unimp(eid, name, _unused_dumpfile): + "Unimplimented decoder, will trigger exit" + print "%s not handled - will now stop" % (name) + return False + +# Checkpoint decoder +def swallow_async_qword(eid, name, dumpfile): + "Swallow a qword of data without looking at it" + step_id = read_qword(dumpfile) + print " %s(%d) @ %d" % (name, eid, step_id) + return True + +async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword), + Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp), + Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp), + Decoder(3, "REPLAY_ASYNC_CHAR_READ", decode_unimp), + Decoder(4, "REPLAY_ASYNC_EVENT_BLOCK", decode_unimp), + Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp), +] +# See replay_read_events/replay_read_event +def decode_async(eid, name, dumpfile): + """Decode an ASYNC event""" + + print_event(eid, name) + + async_event_kind = read_byte(dumpfile) + async_event_checkpoint = read_byte(dumpfile) + + if async_event_checkpoint != replay_state.current_checkpoint: + print " mismatch between checkpoint %d and async data %d" % ( + replay_state.current_checkpoint, async_event_checkpoint) + return True + + return call_decode(async_decode_table, async_event_kind, dumpfile) + + +def decode_instruction(eid, name, dumpfile): + ins_diff = read_dword(dumpfile) + print_event(eid, name, "0x%x" % (ins_diff)) + return True + +def decode_audio_out(eid, name, dumpfile): + audio_data = read_dword(dumpfile) + print_event(eid, name, "%d" % (audio_data)) + return True + +def decode_checkpoint(eid, name, dumpfile): + """Decode a checkpoint. + + Checkpoints contain a series of async events with their own specific data. + """ + replay_state.set_checkpoint() + # save event count as we peek ahead + event_number = replay_state.event_count + next_event = read_event(dumpfile) + + # if the next event is EVENT_ASYNC there are a bunch of + # async events to read, otherwise we are done + if next_event != 3: + print_event(eid, name, "no additional data", event_number) + else: + print_event(eid, name, "more data follows", event_number) + + replay_state.reuse_event(next_event) + return True + +def decode_checkpoint_init(eid, name, dumpfile): + print_event(eid, name) + return True + +def decode_interrupt(eid, name, dumpfile): + print_event(eid, name) + return True + +def decode_clock(eid, name, dumpfile): + clock_data = read_qword(dumpfile) + print_event(eid, name, "0x%x" % (clock_data)) + return True + + +# pre-MTTCG merge +v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction), + Decoder(1, "EVENT_INTERRUPT", decode_interrupt), + Decoder(2, "EVENT_EXCEPTION", decode_unimp), + Decoder(3, "EVENT_ASYNC", decode_async), + Decoder(4, "EVENT_SHUTDOWN", decode_unimp), + Decoder(5, "EVENT_CHAR_WRITE", decode_unimp), + Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp), + Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp), + Decoder(8, "EVENT_CLOCK_HOST", decode_clock), + Decoder(9, "EVENT_CLOCK_VIRTUAL_RT", decode_clock), + Decoder(10, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint), + Decoder(11, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint), + Decoder(12, "EVENT_CP_RESET_REQUESTED", decode_checkpoint), + Decoder(13, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint), + Decoder(14, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint), + Decoder(15, "EVENT_CP_CLOCK_HOST", decode_checkpoint), + Decoder(16, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint), + Decoder(17, "EVENT_CP_INIT", decode_checkpoint_init), + Decoder(18, "EVENT_CP_RESET", decode_checkpoint), +] + +# post-MTTCG merge, AUDIO support added +v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction), + Decoder(1, "EVENT_INTERRUPT", decode_interrupt), + Decoder(2, "EVENT_EXCEPTION", decode_unimp), + Decoder(3, "EVENT_ASYNC", decode_async), + Decoder(4, "EVENT_SHUTDOWN", decode_unimp), + Decoder(5, "EVENT_CHAR_WRITE", decode_unimp), + Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp), + Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp), + Decoder(8, "EVENT_AUDIO_OUT", decode_audio_out), + Decoder(9, "EVENT_AUDIO_IN", decode_unimp), + Decoder(10, "EVENT_CLOCK_HOST", decode_clock), + Decoder(11, "EVENT_CLOCK_VIRTUAL_RT", decode_clock), + Decoder(12, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint), + Decoder(13, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint), + Decoder(14, "EVENT_CP_RESET_REQUESTED", decode_checkpoint), + Decoder(15, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint), + Decoder(16, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint), + Decoder(17, "EVENT_CP_CLOCK_HOST", decode_checkpoint), + Decoder(18, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint), + Decoder(19, "EVENT_CP_INIT", decode_checkpoint_init), + Decoder(20, "EVENT_CP_RESET", decode_checkpoint), +] + +# Shutdown cause added +v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction), + Decoder(1, "EVENT_INTERRUPT", decode_interrupt), + Decoder(2, "EVENT_EXCEPTION", decode_unimp), + Decoder(3, "EVENT_ASYNC", decode_async), + Decoder(4, "EVENT_SHUTDOWN", decode_unimp), + Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp), + Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp), + Decoder(7, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp), + Decoder(8, "EVENT_SHUTDOWN_HOST_UI", decode_unimp), + Decoder(9, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp), + Decoder(10, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp), + Decoder(11, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp), + Decoder(12, "EVENT_SHUTDOWN___MAX", decode_unimp), + Decoder(13, "EVENT_CHAR_WRITE", decode_unimp), + Decoder(14, "EVENT_CHAR_READ_ALL", decode_unimp), + Decoder(15, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp), + Decoder(16, "EVENT_AUDIO_OUT", decode_audio_out), + Decoder(17, "EVENT_AUDIO_IN", decode_unimp), + Decoder(18, "EVENT_CLOCK_HOST", decode_clock), + Decoder(19, "EVENT_CLOCK_VIRTUAL_RT", decode_clock), + Decoder(20, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint), + Decoder(21, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint), + Decoder(22, "EVENT_CP_RESET_REQUESTED", decode_checkpoint), + Decoder(23, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint), + Decoder(24, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint), + Decoder(25, "EVENT_CP_CLOCK_HOST", decode_checkpoint), + Decoder(26, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint), + Decoder(27, "EVENT_CP_INIT", decode_checkpoint_init), + Decoder(28, "EVENT_CP_RESET", decode_checkpoint), +] + +def parse_arguments(): + "Grab arguments for script" + parser = argparse.ArgumentParser() + parser.add_argument("-f", "--file", help='record/replay dump to read from', + required=True) + return parser.parse_args() + +def decode_file(filename): + "Decode a record/replay dump" + dumpfile = open(filename, "rb") + + # read and throwaway the header + version = read_dword(dumpfile) + junk = read_qword(dumpfile) + + print "HEADER: version 0x%x" % (version) + + if version == 0xe02007: + event_decode_table = v7_event_table + replay_state.checkpoint_start = 12 + elif version == 0xe02006: + event_decode_table = v6_event_table + replay_state.checkpoint_start = 12 + else: + event_decode_table = v5_event_table + replay_state.checkpoint_start = 10 + + try: + decode_ok = True + while decode_ok: + event = read_event(dumpfile) + decode_ok = call_decode(event_decode_table, event, dumpfile) + finally: + dumpfile.close() + +if __name__ == "__main__": + args = parse_arguments() + decode_file(args.file) -- cgit v1.2.1 From 89e46eb477113550485bc24264d249de9fd1260a Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:53:16 +0300 Subject: replay: don't process async events when warping the clock Virtual clock is warped from iothread and vcpu thread. When the hardware events associated with warp checkpoint, then interrupt delivering may be non-deterministic if checkpoint is processed in different threads in record and replay. This patch disables event processing for clock warp checkpoint and leaves all hardware events to other checkpoints (e.g., virtual clock). Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095316.1060.4134.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- replay/replay-events.c | 1 + replay/replay.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index 54dd9d2606..3d5fc8a479 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -205,6 +205,7 @@ static void replay_save_event(Event *event, int checkpoint) void replay_save_events(int checkpoint) { g_assert(replay_mutex_locked()); + g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START); while (!QTAILQ_EMPTY(&events_list)) { Event *event = QTAILQ_FIRST(&events_list); replay_save_event(event, checkpoint); diff --git a/replay/replay.c b/replay/replay.c index eae8daf18a..8228261401 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -211,7 +211,12 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) } else if (replay_mode == REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); replay_put_event(EVENT_CHECKPOINT + checkpoint); - replay_save_events(checkpoint); + /* This checkpoint belongs to several threads. + Processing events from different threads is + non-deterministic */ + if (checkpoint != CHECKPOINT_CLOCK_WARP_START) { + replay_save_events(checkpoint); + } res = true; } out: -- cgit v1.2.1 From 0b30dc0164eeb4df059b5e5ce8c5796152b821e0 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:53:22 +0300 Subject: replay: save vmstate of the asynchronous events This patch fixes saving and loading the snapshots in the replay mode. It is required for the snapshots created in the moment when the header of the asynchronous event is read. This information was not saved in the snapshot. After loading the vmstate replay continued with the file offset passed the event header. The event header is lost in this case and replay hangs. Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095322.1060.53929.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini --- replay/replay-events.c | 44 +++++++++++++++++++++----------------------- replay/replay-internal.h | 6 ++++++ replay/replay-snapshot.c | 3 +++ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index 3d5fc8a479..707de3867b 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -27,10 +27,6 @@ typedef struct Event { } Event; static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); -static unsigned int read_event_kind = -1; -static uint64_t read_id = -1; -static int read_checkpoint = -1; - static bool events_enabled; /* Functions */ @@ -218,58 +214,60 @@ void replay_save_events(int checkpoint) static Event *replay_read_event(int checkpoint) { Event *event; - if (read_event_kind == -1) { - read_checkpoint = replay_get_byte(); - read_event_kind = replay_get_byte(); - read_id = -1; + if (replay_state.read_event_kind == -1) { + replay_state.read_event_checkpoint = replay_get_byte(); + replay_state.read_event_kind = replay_get_byte(); + replay_state.read_event_id = -1; replay_check_error(); } - if (checkpoint != read_checkpoint) { + if (checkpoint != replay_state.read_event_checkpoint) { return NULL; } /* Events that has not to be in the queue */ - switch (read_event_kind) { + switch (replay_state.read_event_kind) { case REPLAY_ASYNC_EVENT_BH: - if (read_id == -1) { - read_id = replay_get_qword(); + if (replay_state.read_event_id == -1) { + replay_state.read_event_id = replay_get_qword(); } break; case REPLAY_ASYNC_EVENT_INPUT: event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; + event->event_kind = replay_state.read_event_kind; event->opaque = replay_read_input_event(); return event; case REPLAY_ASYNC_EVENT_INPUT_SYNC: event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; + event->event_kind = replay_state.read_event_kind; event->opaque = 0; return event; case REPLAY_ASYNC_EVENT_CHAR_READ: event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; + event->event_kind = replay_state.read_event_kind; event->opaque = replay_event_char_read_load(); return event; case REPLAY_ASYNC_EVENT_BLOCK: - if (read_id == -1) { - read_id = replay_get_qword(); + if (replay_state.read_event_id == -1) { + replay_state.read_event_id = replay_get_qword(); } break; case REPLAY_ASYNC_EVENT_NET: event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; + event->event_kind = replay_state.read_event_kind; event->opaque = replay_event_net_load(); return event; default: - error_report("Unknown ID %d of replay event", read_event_kind); + error_report("Unknown ID %d of replay event", + replay_state.read_event_kind); exit(1); break; } QTAILQ_FOREACH(event, &events_list, events) { - if (event->event_kind == read_event_kind - && (read_id == -1 || read_id == event->id)) { + if (event->event_kind == replay_state.read_event_kind + && (replay_state.read_event_id == -1 + || replay_state.read_event_id == event->id)) { break; } } @@ -295,7 +293,7 @@ void replay_read_events(int checkpoint) break; } replay_finish_event(); - read_event_kind = -1; + replay_state.read_event_kind = -1; replay_run_event(event); g_free(event); @@ -304,7 +302,7 @@ void replay_read_events(int checkpoint) void replay_init_events(void) { - read_event_kind = -1; + replay_state.read_event_kind = -1; } void replay_finish_events(void) diff --git a/replay/replay-internal.h b/replay/replay-internal.h index d4037058e4..ac4b27b674 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -80,6 +80,12 @@ typedef struct ReplayState { uint64_t block_request_id; /*! Prior value of the host clock */ uint64_t host_clock_last; + /*! Asynchronous event type read from the log */ + int32_t read_event_kind; + /*! Asynchronous event id read from the log */ + uint64_t read_event_id; + /*! Asynchronous event checkpoint id read from the log */ + int32_t read_event_checkpoint; } ReplayState; extern ReplayState replay_state; diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index e0b2204765..2ab85cfc60 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -57,6 +57,9 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), VMSTATE_UINT64(host_clock_last, ReplayState), + VMSTATE_INT32(read_event_kind, ReplayState), + VMSTATE_UINT64(read_event_id, ReplayState), + VMSTATE_INT32(read_event_checkpoint, ReplayState), VMSTATE_END_OF_LIST() }, }; -- cgit v1.2.1 From 7273db9d28d5e1b7a6c202a5054861c1f0bcc446 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:53:33 +0300 Subject: replay: update documentation This patch clarifies the description of the record/replay feature in docs/replay.txt Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095333.1060.1331.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- docs/replay.txt | 72 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/docs/replay.txt b/docs/replay.txt index 959633e7ea..2e21e9ccb0 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -7,14 +7,10 @@ See the COPYING file in the top-level directory. Record/replay ------------- -Record/replay functions are used for the reverse execution and deterministic -replay of qemu execution. This implementation of deterministic replay can -be used for deterministic debugging of guest code through a gdb remote -interface. - +Record/replay functions are used for the deterministic replay of qemu execution. Execution recording writes a non-deterministic events log, which can be later used for replaying the execution anywhere and for unlimited number of times. -It also supports checkpointing for faster rewinding during reverse debugging. +It also supports checkpointing for faster rewind to the specific replay moment. Execution replaying reads the log and replays all non-deterministic events including external input, hardware clocks, and interrupts. @@ -28,16 +24,36 @@ Deterministic replay has the following features: input devices. Usage of the record/replay: - * First, record the execution, by adding the following arguments to the command line: - '-icount shift=7,rr=record,rrfile=replay.bin -net none'. - Block devices' images are not actually changed in the recording mode, + * First, record the execution with the following command line: + qemu-system-i386 \ + -icount shift=7,rr=record,rrfile=replay.bin \ + -drive file=disk.qcow2,if=none,id=img-direct \ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ + -device ide-hd,drive=img-blkreplay \ + -netdev user,id=net1 -device rtl8139,netdev=net1 \ + -object filter-replay,id=replay,netdev=net1 + * After recording, you can replay it by using another command line: + qemu-system-i386 \ + -icount shift=7,rr=replay,rrfile=replay.bin \ + -drive file=disk.qcow2,if=none,id=img-direct \ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ + -device ide-hd,drive=img-blkreplay \ + -netdev user,id=net1 -device rtl8139,netdev=net1 \ + -object filter-replay,id=replay,netdev=net1 + The only difference with recording is changing the rr option + from record to replay. + * Block device images are not actually changed in the recording mode, because all of the changes are written to the temporary overlay file. - * Then you can replay it by using another command - line option: '-icount shift=7,rr=replay,rrfile=replay.bin -net none' - * '-net none' option should also be specified if network replay patches - are not applied. - -Papers with description of deterministic replay implementation: + This behavior is enabled by using blkreplay driver. It should be used + for every enabled block device, as described in 'Block devices' section. + * '-net none' option should be specified when network is not used, + because QEMU adds network card by default. When network is needed, + it should be configured explicitly with replay filter, as described + in 'Network devices' section. + * Interaction with audio devices and serial ports are recorded and replayed + automatically when such devices are enabled. + +Academic papers with description of deterministic replay implementation: http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html http://dl.acm.org/citation.cfm?id=2786805.2803179 @@ -46,8 +62,11 @@ Modifications of qemu include: * saving different asynchronous events (e.g. system shutdown) into the log * synchronization of the bottom halves execution * synchronization of the threads from thread pool - * recording/replaying user input (mouse and keyboard) + * recording/replaying user input (mouse, keyboard, and microphone) * adding internal checkpoints for cpu and io synchronization + * network filter for recording and replaying the packets + * block driver for making block layer deterministic + * serial port input record and replay Locking and thread synchronisation ---------------------------------- @@ -77,12 +96,11 @@ Non-deterministic events Our record/replay system is based on saving and replaying non-deterministic events (e.g. keyboard input) and simulating deterministic ones (e.g. reading from HDD or memory of the VM). Saving only non-deterministic events makes -log file smaller, simulation faster, and allows using reverse debugging even -for realtime applications. +log file smaller and simulation faster. The following non-deterministic data from peripheral devices is saved into the log: mouse and keyboard input, network packets, audio controller input, -USB packets, serial port input, and hardware clocks (they are non-deterministic +serial port input, and hardware clocks (they are non-deterministic too, because their values are taken from the host machine). Inputs from simulated hardware, memory of VM, software interrupts, and execution of instructions are not saved into the log, because they are deterministic and @@ -205,7 +223,7 @@ Block devices record/replay module intercepts calls of bdrv coroutine functions at the top of block drivers stack. To record and replay block operations the drive must be configured as following: - -drive file=disk.qcow,if=none,id=img-direct + -drive file=disk.qcow2,if=none,id=img-direct -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay -device ide-hd,drive=img-blkreplay @@ -234,6 +252,12 @@ This snapshot is created at start of recording and restored at start of replaying. It also can be loaded while replaying to roll back the execution. +Use QEMU monitor to create additional snapshots. 'savevm ' command +created the snapshot and 'loadvm ' restores it. To prevent corruption +of the original disk image, use overlay files linked to the original images. +Therefore all new snapshots (including the starting one) will be saved in +overlays and the original image remains unchanged. + Network devices --------------- @@ -255,6 +279,14 @@ Audio data is recorded and replay automatically. The command line for recording and replaying must contain identical specifications of audio hardware, e.g.: -soundhw ac97 +Serial ports +------------ + +Serial ports input is recorded and replay automatically. The command lines +for recording and replaying must contain identical number of ports in record +and replay modes, but their backends may differ. +E.g., '-serial stdio' in record mode, and '-serial null' in replay mode. + Replay log format ----------------- -- cgit v1.2.1 From 0790f86861079b1932679d0f011e431aaf4ee9e2 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 27 Feb 2018 12:53:38 +0300 Subject: tcg: fix cpu_io_recompile cpu_io_recompile() function was broken by the commit 9b990ee5a3cc6aa38f81266fb0c6ef37a36c45b9. Instead of regenerating the block starting from PC of the original block, it just set the instruction counter for TCG. In most cases this was unnoticed, but in icount mode there was an exception for incorrect usage of CF_LAST_IO flag. This patch recovers recompilation of the original block and also configures translation for executing single IO instruction which caused a recompilation. Signed-off-by: Pavel Dovgalyuk Message-Id: <20180227095338.1060.27385.stgit@pasha-VirtualBox> Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- accel/tcg/translate-all.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 67795cd78c..5ad1b919bc 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1728,7 +1728,8 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) CPUArchState *env = cpu->env_ptr; #endif TranslationBlock *tb; - uint32_t n; + uint32_t n, flags; + target_ulong pc, cs_base; tb_lock(); tb = tb_find_pc(retaddr); @@ -1766,8 +1767,14 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cpu_abort(cpu, "TB too big during recompile"); } - /* Adjust the execution state of the next TB. */ - cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | n; + pc = tb->pc; + cs_base = tb->cs_base; + flags = tb->flags; + tb_phys_invalidate(tb, -1); + + /* Execute one IO instruction without caching + instead of creating large TB. */ + cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | CF_NOCACHE | 1; if (tb->cflags & CF_NOCACHE) { if (tb->orig_tb) { @@ -1778,6 +1785,11 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) tb_remove(tb); } + /* Generate new TB instead of the current one. */ + /* FIXME: In theory this could raise an exception. In practice + we have already translated the block once so it's probably ok. */ + tb_gen_code(cpu, pc, cs_base, flags, curr_cflags() | CF_LAST_IO | n); + /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not * the first in the TB) then we end up generating a whole new TB and * repeating the fault, which is horribly inefficient. -- cgit v1.2.1