From 3e996cc58334be1c3f1be524b4f048566eccbb1d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 29 Jan 2016 13:18:56 +0000 Subject: [PATCH 01/45] Fix virtio migration I misunderstood the vmstate macro definition when I reworked the virtio .get/.put. The VMSTATE_STRUCT_VARRAY_KNOWN, was described as being for "a variable length array (i.e. _type *_field) but we know the length". However it actually specified operation for arrays embedded in the struct (i.e. _type _field[]) since it lacked the VMS_POINTER flag. This caused offset calculation to be completely off, examining and potentially sending random data instead of the VirtQueue content. Replace the otherwise unused VMSTATE_STRUCT_VARRAY_KNOWN with a VMSTATE_STRUCT_VARRAY_POINTER_KNOWN that includes the VMS_POINTER flag (so now actually doing what it advertises) and use it in the virtio migration code. Fixes and description as per Sascha's suggestions/debug. Signed-off-by: Dr. David Alan Gilbert Reported-by: Sascha Silbe Tested-By: Sascha Silbe Reviewed-By: Sascha Silbe Fixes: 50e5ae4dc3e4f21e874512f9e87b93b5472d26e0 Fixes: 2cf0148674430b6693c60d42b7eef721bfa9509f Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Cornelia Huck --- hw/virtio/virtio.c | 8 ++++---- include/migration/vmstate.h | 26 +++++++++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 63a7b6d7ba..0603793e34 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1143,8 +1143,8 @@ static const VMStateDescription vmstate_virtio_virtqueues = { .minimum_version_id = 1, .needed = &virtio_virtqueue_needed, .fields = (VMStateField[]) { - VMSTATE_STRUCT_VARRAY_KNOWN(vq, struct VirtIODevice, VIRTIO_QUEUE_MAX, - 0, vmstate_virtqueue, VirtQueue), + VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice, + VIRTIO_QUEUE_MAX, 0, vmstate_virtqueue, VirtQueue), VMSTATE_END_OF_LIST() } }; @@ -1165,8 +1165,8 @@ static const VMStateDescription vmstate_virtio_ringsize = { .minimum_version_id = 1, .needed = &virtio_ringsize_needed, .fields = (VMStateField[]) { - VMSTATE_STRUCT_VARRAY_KNOWN(vq, struct VirtIODevice, VIRTIO_QUEUE_MAX, - 0, vmstate_ringsize, VirtQueue), + VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice, + VIRTIO_QUEUE_MAX, 0, vmstate_ringsize, VirtQueue), VMSTATE_END_OF_LIST() } }; diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index a4b81bb5f6..7246f29afe 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -386,19 +386,6 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_array(_state, _field, _type, _num),\ } -/* a variable length array (i.e. _type *_field) but we know the - * length - */ -#define VMSTATE_STRUCT_VARRAY_KNOWN(_field, _state, _num, _version, _vmsd, _type) { \ - .name = (stringify(_field)), \ - .num = (_num), \ - .version_id = (_version), \ - .vmsd = &(_vmsd), \ - .size = sizeof(_type), \ - .flags = VMS_STRUCT|VMS_ARRAY, \ - .offset = offsetof(_state, _field), \ -} - #define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ @@ -409,6 +396,19 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = offsetof(_state, _field), \ } +/* a variable length array (i.e. _type *_field) but we know the + * length + */ +#define VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(_field, _state, _num, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .num = (_num), \ + .version_id = (_version), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_ARRAY|VMS_POINTER, \ + .offset = offsetof(_state, _field), \ +} + #define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \ .name = (stringify(_field)), \ .version_id = 0, \ From 41fa5c0410a13d804eabf6ca7cc5c8e21b718a03 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 22 Jan 2016 15:36:06 +0100 Subject: [PATCH 02/45] pc: acpi: merge SSDT into DSDT Since both tables are built dynamically now, there is no point in keeping ASL in them in separate tables. So do the same as we do for ARM where we have only DSDT table, i.e. move SSDT ASL into DSDT and drop SSDT altogether. This patch doesn't change moved SSDT ASL in any way, but it opens a way to relatively independently simplify generated ASL on per device/subsystem basis in followup series. It also simplifies bios-tables-test where expected SSDT blobs could be dropped and only DSDT ones have to be maintained. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 246 +++++++++++++++++++------------------------ 1 file changed, 111 insertions(+), 135 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 739cfa3bb9..2028ed78da 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1935,24 +1935,113 @@ static Aml *build_q35_osc_method(void) } static void -build_ssdt(GArray *table_data, GArray *linker, +build_dsdt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc, PcPciInfo *pci, PcGuestInfo *guest_info) { + CrsRangeEntry *entry; + Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; + GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); + GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); MachineState *machine = MACHINE(qdev_get_machine()); uint32_t nr_mem = machine->ram_slots; - Aml *ssdt, *sb_scope, *scope, *pkg, *dev, *method, *crs, *field; - PCIBus *bus = NULL; - GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); - GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); - CrsRangeEntry *entry; int root_bus_limit = 0xFF; + PCIBus *bus = NULL; int i; - ssdt = init_aml_allocator(); + dsdt = init_aml_allocator(); /* Reserve space for header */ - acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); + acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); + + build_dbg_aml(dsdt); + if (misc->is_piix4) { + sb_scope = aml_scope("_SB"); + dev = aml_device("PCI0"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(1))); + aml_append(sb_scope, dev); + aml_append(dsdt, sb_scope); + + build_hpet_aml(dsdt); + build_piix4_pm(dsdt); + build_piix4_isa_bridge(dsdt); + build_isa_devices_aml(dsdt); + build_piix4_pci_hotplug(dsdt); + build_piix4_pci0_int(dsdt); + } else { + sb_scope = aml_scope("_SB"); + aml_append(sb_scope, + aml_operation_region("PCST", AML_SYSTEM_IO, 0xae00, 0x0c)); + aml_append(sb_scope, + aml_operation_region("PCSB", AML_SYSTEM_IO, 0xae0c, 0x01)); + field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_named_field("PCIB", 8)); + aml_append(sb_scope, field); + aml_append(dsdt, sb_scope); + + sb_scope = aml_scope("_SB"); + dev = aml_device("PCI0"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); + aml_append(dev, aml_name_decl("_ADR", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(1))); + aml_append(dev, aml_name_decl("SUPP", aml_int(0))); + aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + aml_append(dev, build_q35_osc_method()); + aml_append(sb_scope, dev); + aml_append(dsdt, sb_scope); + + build_hpet_aml(dsdt); + build_q35_isa_bridge(dsdt); + build_isa_devices_aml(dsdt); + build_q35_pci0_int(dsdt); + } + + build_cpu_hotplug_aml(dsdt); + build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, + pm->mem_hp_io_len); + + scope = aml_scope("_GPE"); + { + aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); + + aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED)); + + if (misc->is_piix4) { + method = aml_method("_E01", 0, AML_NOTSERIALIZED); + aml_append(method, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + aml_append(scope, method); + } else { + aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED)); + } + + method = aml_method("_E02", 0, AML_NOTSERIALIZED); + aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD)); + aml_append(scope, method); + + method = aml_method("_E03", 0, AML_NOTSERIALIZED); + aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH)); + aml_append(scope, method); + + aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED)); + } + aml_append(dsdt, scope); bus = PC_MACHINE(machine)->bus; if (bus) { @@ -1984,7 +2073,7 @@ build_ssdt(GArray *table_data, GArray *linker, io_ranges, mem_ranges); aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); - aml_append(ssdt, scope); + aml_append(dsdt, scope); } } @@ -2068,7 +2157,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); } - aml_append(ssdt, scope); + aml_append(dsdt, scope); /* create S3_ / S4_ / S5_ packages if necessary */ scope = aml_scope("\\"); @@ -2097,7 +2186,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(pkg, aml_int(0)); /* reserved */ aml_append(pkg, aml_int(0)); /* reserved */ aml_append(scope, aml_name_decl("_S5", pkg)); - aml_append(ssdt, scope); + aml_append(dsdt, scope); if (misc->applesmc_io_base) { scope = aml_scope("\\_SB.PCI0.ISA"); @@ -2116,7 +2205,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); - aml_append(ssdt, scope); + aml_append(dsdt, scope); } if (misc->pvpanic_port) { @@ -2150,7 +2239,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(dev, method); aml_append(scope, dev); - aml_append(ssdt, scope); + aml_append(dsdt, scope); } sb_scope = aml_scope("\\_SB"); @@ -2189,14 +2278,14 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(sb_scope, scope); } } - aml_append(ssdt, sb_scope); + aml_append(dsdt, sb_scope); } /* copy AML table into ACPI tables blob and patch header there */ - g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len); + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); build_header(linker, table_data, - (void *)(table_data->data + table_data->len - ssdt->buf->len), - "SSDT", ssdt->buf->len, 1, NULL); + (void *)(table_data->data + table_data->len - dsdt->buf->len), + "DSDT", dsdt->buf->len, 1, NULL); free_aml_allocator(); } @@ -2422,116 +2511,6 @@ build_dmar_q35(GArray *table_data, GArray *linker) "DMAR", table_data->len - dmar_start, 1, NULL); } -static void -build_dsdt(GArray *table_data, GArray *linker, - AcpiPmInfo *pm, AcpiMiscInfo *misc) -{ - Aml *dsdt, *sb_scope, *scope, *dev, *method, *field; - MachineState *machine = MACHINE(qdev_get_machine()); - uint32_t nr_mem = machine->ram_slots; - - dsdt = init_aml_allocator(); - - /* Reserve space for header */ - acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); - - build_dbg_aml(dsdt); - if (misc->is_piix4) { - sb_scope = aml_scope("_SB"); - dev = aml_device("PCI0"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - aml_append(sb_scope, dev); - aml_append(dsdt, sb_scope); - - build_hpet_aml(dsdt); - build_piix4_pm(dsdt); - build_piix4_isa_bridge(dsdt); - build_isa_devices_aml(dsdt); - build_piix4_pci_hotplug(dsdt); - build_piix4_pci0_int(dsdt); - } else { - sb_scope = aml_scope("_SB"); - aml_append(sb_scope, - aml_operation_region("PCST", AML_SYSTEM_IO, 0xae00, 0x0c)); - aml_append(sb_scope, - aml_operation_region("PCSB", AML_SYSTEM_IO, 0xae0c, 0x01)); - field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_named_field("PCIB", 8)); - aml_append(sb_scope, field); - aml_append(dsdt, sb_scope); - - sb_scope = aml_scope("_SB"); - dev = aml_device("PCI0"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); - aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); - aml_append(dev, aml_name_decl("_ADR", aml_int(0))); - aml_append(dev, aml_name_decl("_UID", aml_int(1))); - aml_append(dev, aml_name_decl("SUPP", aml_int(0))); - aml_append(dev, aml_name_decl("CTRL", aml_int(0))); - aml_append(dev, build_q35_osc_method()); - aml_append(sb_scope, dev); - aml_append(dsdt, sb_scope); - - build_hpet_aml(dsdt); - build_q35_isa_bridge(dsdt); - build_isa_devices_aml(dsdt); - build_q35_pci0_int(dsdt); - } - - build_cpu_hotplug_aml(dsdt); - build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, - pm->mem_hp_io_len); - - scope = aml_scope("_GPE"); - { - aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); - - aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED)); - - if (misc->is_piix4) { - method = aml_method("_E01", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); - aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); - aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); - aml_append(scope, method); - } else { - aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED)); - } - - method = aml_method("_E02", 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD)); - aml_append(scope, method); - - method = aml_method("_E03", 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH)); - aml_append(scope, method); - - aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED)); - aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED)); - } - aml_append(dsdt, scope); - - /* copy AML table into ACPI tables blob and patch header there */ - g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); - build_header(linker, table_data, - (void *)(table_data->data + table_data->len - dsdt->buf->len), - "DSDT", dsdt->buf->len, 1, NULL); - free_aml_allocator(); -} - static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { @@ -2611,7 +2590,7 @@ static void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; - unsigned facs, ssdt, dsdt, rsdt; + unsigned facs, dsdt, rsdt, fadt; AcpiCpuInfo cpu; AcpiPmInfo pm; AcpiMiscInfo misc; @@ -2644,7 +2623,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, &pm, &misc); + build_dsdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci, + guest_info); /* Count the size of the DSDT and SSDT, we will need it for legacy * sizing of ACPI tables. @@ -2652,14 +2632,10 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) aml_len += tables_blob->len - dsdt; /* ACPI tables pointed to by RSDT */ + fadt = tables_blob->len; acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables->linker, &pm, facs, dsdt); - - ssdt = tables_blob->len; - acpi_add_table(table_offsets, tables_blob); - build_ssdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci, - guest_info); - aml_len += tables_blob->len - ssdt; + aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, &cpu, guest_info); From caf50c7166a6ed96c462ab5db4b495e1234e4cc6 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 22 Jan 2016 15:36:07 +0100 Subject: [PATCH 03/45] tests: pc: acpi: drop not needed 'expected SSDT' blobs Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-test-data/pc/SSDT | Bin 2486 -> 0 bytes tests/acpi-test-data/pc/SSDT.bridge | Bin 4345 -> 0 bytes tests/acpi-test-data/q35/SSDT | Bin 691 -> 0 bytes tests/acpi-test-data/q35/SSDT.bridge | Bin 708 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/acpi-test-data/pc/SSDT delete mode 100644 tests/acpi-test-data/pc/SSDT.bridge delete mode 100644 tests/acpi-test-data/q35/SSDT delete mode 100644 tests/acpi-test-data/q35/SSDT.bridge diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT deleted file mode 100644 index 210d6a71e58aa34ce8e94121d25bcf58c3bd503c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2486 zcma)-Pjk~o7{=eVMWU=_A{&JSLWr(#pbjB{-fT-EjvFaES~~;d%;?ZzYGyhO1LeTv zl7zwSyXMF3m{RqAF%6I5Yn^WEQmHaw6upNAm_tEp)XaBFX4tu{Y0Ej=^`$0$h z?I$YG_)Y)-mFeG&YKQkS-Og07+px1B)wTA#{Nd*+lpM4HCiDIt{ zpndMlbag`DUq3Aa6h452$)rLk{z{NL)FS=t$>g_xi{kHpzk$J7VC|>~+wbg#Rh6hl ztFaAs)<;F}{g=;P9ld_}?Xy?-QukW2QuMSc<&O9?{xlXAg>)^|QR(MGaBzO-=*Jh| zzy9ujv*06q6y6(f?;KJ~n^}F%64+@hKgjB~B}=lDt1WV90B-BuAx+=l>>KMI&7n#o zop-@${UPUyF$AjrWzCOaEPNcwiAr@(RA4Oq!KsrAd}K{`@OCp$jYctbo|DC`9()K? z+yWFhGbD5mylNJ88v;etg`rnVdXJx$-pgNxFrw#-AoKlmx}s2!dm;$0X}r#dvh^$)Qykw-PlGKm$jlBjm*wkVT$6e-k1v9 zeN=zApF_RQYIuqz6#Vc*X6h3}HaL%_bD>kGe08n-k1 zC%L}x^AY35WFJ2!BOP4wY1FvIWPpY$cai5i!E=AV#8-&~YE diff --git a/tests/acpi-test-data/pc/SSDT.bridge b/tests/acpi-test-data/pc/SSDT.bridge deleted file mode 100644 index 6e6660b1fbe0bdb7fe0b257cb53c31fa9bb21a14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4345 zcmeH}KX2Pc7{>1;#%4}bOeu8iIC0FOL!H5u<3DjXNhD)gG3f(OG7``zha#u~6itvc z1p+U&3aH)t1w3SqK0^Bu`Vlhp8x&}rrRw{VdSws3qGJYWpzh)G<8yc9@m?zBcRt#T zakqKkwUpa@B0UA?IAaXk_-_Z5qqS5uQ|ay1%+!ljr8z6U`?<^t7TAo9@W6NZxpi)F z6V7w1h^PJr``nu7@(95{e_CKH_ZbsxG%6tqzXHn~>=A$FX!PqpdGoiw-m;|c8M`uo z{#$!~Sw^zfsBJSd?SjJd?yG07U%Yws^|RM-Qgs@ll#jG5#4i6Z{4nGOhO`aYlJQj` zFgdsN;`^81zWL@qv)Fs~o;z=uy?TT_ZKTy1gTtVqy_r@`Lli_IQ(NfZ1Z@A~5#GL} z|JYc=dnn^TWkawUzl)iC4xa4(zwU=@$X%GqiHuc;m)KCa$*GkIIHYwu`EkROwOW4b z94ieQ9rn(XVS|ByJA*=Xm{U%Jc8!Aw+N|ePqRykIg){L>j}7qh=cXqQqH2+IJ2a2J zDAMx}Thcc}KZ;?(xDvAa3(rxoMI2O1hA|9Eh{fb|1w}E8oBJ*tT5#CM);_f4lN3h1 zj6j3cMHr}*hkKFYVH_UvFleVdIi1h1R{>mg5FElmd9E`P;y~^CAK7Ybf(wteq-wR) zOdEa-;=WoR3s`>z=D?F#_u0Fw@qii|*hu;ZKdAMc{7Qg}%)~&R^gqi3RX2ipVysim zZkP0eHXChcYwF$MgD5X{it?1A%DYZ&yRf|&UO+s(# z&<3T#TbVxsM~hPGJfZVCv`MMA2)(66DRqI+1s&>9>LQ_wT9i_66M9>R`jomv=#mzt z)H{UU(V+pQ-X-*|7Nyi>LYH;uBTBtT=shh;sVju8T!lK(vVRzL3TLI`9%lpGWuKo} z$33W-Aa=&W00Db=?wBaZu|dF|mpd*Ba_S&p-^!g66zG(XdnMSD2MRWyvBI7?LnT-4Gu%6zMJ>H+)e{`m6Z(rX?%C1JjZ-KVPlkrvx(p0-RC(E&u=k diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT deleted file mode 100644 index 0970c67ddb1456707c0111f7e5e659ef385af408..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 691 zcmaJ<&2G~`5S~pUV{JB)8wF7g2w&k)41tOhs=apOgsijjx>b=Q?EzI33AL!DhaQkf zkbpZcz@cxz1HdD2%zJPkC(MjZIkJcG_sx&K`LQu^@wElO-bOQ-8b3PF(x8t40Ac!i zV=>>dCbC+N1J}yjY(&@i@uwcN1cm`BGHk@wVl9}9ekR)F`i0@O_{Vz{CI0+)1E7fm zaHy&-rQ&Nr9U(<}->d4|@4xWL1(ZwK8R-P|({bF>nGV8W8(h1GjQsxT;n~Ug>GQ)g zbebaM-KNtX=OgAjzQeo=@b1hhI<$SK!%ztEL)&*dyv1<`$R1IIM7_z)IgMN{pLVur zZk;El))wIp?lihm@A>J;o7b<-U;I~oC02s@IKw-gn}T&$g8St{)C7&)@yho@se_;y zcOa|^3%Hb8g@6R7Az}&`^lUN-7?NZHM}v*5*nQUe!apCu2P%K*N9!-5TDViyvDI$GfvFlru5W)^u ziLp$LGs9G__L)j1mX(X^O}$C5YL@JyG14D6iW>EHJG9Ai*)>66T^q(Zp7pK?9ybL4 X76t>n!u=R7Yw+L-3~S(MnHBH{@bQ-c diff --git a/tests/acpi-test-data/q35/SSDT.bridge b/tests/acpi-test-data/q35/SSDT.bridge deleted file mode 100644 index a77868861754ce0b3333b2b7bc8091c03a53754d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 708 zcmaJ<&2G~`5T12{u{ImwMn+Uf6~4luxC9U8N?M<3n z7pYlki})vZ8(pdQ!tD6n+t+6=|0}-`3&BF1;k_m^+ zsZ1xHO7a3nr0cDAg1hIiPEBQ66|4iCuUE4>L|UpCOhPmnnhBu^B7I=7>kUeXVVkSe zSf)m~VX9F3Or>MXs@ct^-lSNyo9?4AG7MZrjrzlDw8?7TF;Qea8z%*x^`42IGz9+^ g1_54SD}jp@cyI;!1giNBvvpaBxef%bmU#((0Zb>F0RR91 From 0734fb083cb0a91d17d355acdea16a3413b69b0c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 22 Jan 2016 15:36:08 +0100 Subject: [PATCH 04/45] tests: pc: acpi: add expected DSDT.bridge blobs and update DSDT blobs Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-test-data/pc/DSDT | Bin 3028 -> 5478 bytes tests/acpi-test-data/pc/DSDT.bridge | Bin 0 -> 7337 bytes tests/acpi-test-data/q35/DSDT | Bin 7666 -> 8321 bytes tests/acpi-test-data/q35/DSDT.bridge | Bin 0 -> 8338 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/acpi-test-data/pc/DSDT.bridge create mode 100644 tests/acpi-test-data/q35/DSDT.bridge diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT index c658203db94a7e7db7c36fde99a7075a8d75498d..ec0e642b06967d3ec4d7a7d252b82b916f37a5e0 100644 GIT binary patch delta 2489 zcma)-zi!)B6voe$6q~uCVoIT7Cyrw+9g-oHqu6mbNhEDqHI)lp$!H-19E!9uP}D)v z41ovQE~<9#3wX#Jp-<4xojUXZGUWvdw4SP-L+Z$`kPDOpaX)@Pe)k^UKm23q{R8Q1 zzx(APfO!A2{4F0lLGj>Wq#Kd)b}Lrob#$>YFTeS*02v$T8q-behzt9|78X7ic9tIf zjrN5-)rB#EfBvupkoo`;#^XGpcx51QM5@3VkAL}x+A+Ydf4zqOnU~v90S=(K>laj8 zRqB;Zu%aF+dR~6If28*_T#8zAX( zsP1=AJkaYCfr~H$E>6z64{wsjBW_fw(LcMd*SGLR-D}Hi@;<(j1-F!Z9Tj^)i+UiR z*hiF0Y>wI7l$}L6_8OztOlXx;aW!BCID)we8VfZOTjkh!X6H?@k2%(2)H0%+dY#eh z2^!-PnH|9f$4X|UDRzTnaX+So=L6(Ce-89WkO@x49iBAV{dcpZ4>Hq>>Wn$7*S4Lv7$KrUMnUx z;Mltyd)J6^>?)(HCUl!q@5RjCGqN1J#^~CIP`A0_@3*^|bNhH8Ef~_NcbEtV1s-du zD3f5P2E$n6*_2u*XyM^=cwRUj9glt`INZMc--VvX!ll2N*7 zn}re=afARe12|4@DeIuU(FQNQ*ndKM>@j~r3iK~X(Z;<*o!Q4nv5FQ*Z#kHNcHhkW z-f!O5%)FK9n5{pb0bp0l>qgbdmT%jJi8=-V)TXyqi{Alv&n&NcEE$V4_hB+@*|4ZNh;8UNq1K50~J=tsrpFH+Afk5{+1J0?TEqG4ZbGxT)qn1;>YRycQ zzT%4NmCPon-bT%2nxzU%MXlPEmIN^bp&5r!wObaX0KWPz332zKM)KUPO2f?BP1DQj zOPQaeELxW zXN=?!2Y3M5>sM$rG+eiP(!QN9hGR`Bz;GybzG%dN?`ta)W3XDh=9D~v!-XZ>V$O(h zpW|@fc=rmiP)~sBRhX*Vl?HWYa^t$zBdBHa_G+r8Xu8AvS_E{RJ< zqn_u-R#^Z6Xt4!gt852$AU62`-0t<8Wpe~q6g?5H&1kw|M<0A(*lQcM@x2hkS-ahf z*80Y%=PGMxC^xJoOKQSEf>Ca4SXq~q>&8vcU$>3QTFgC9(*AzX zA!G1>-2>|GUL^GZv<5~*+0$-vI>oxlJ-gY0U^cer2he_2PCRMzz2KuZkHKcJyVKqT zuE17b>un(@fl*Lz+%#dkf1$U<`k7vv$46=hwx6a)QVBts-WHFIH07a28EFjI4nBUc z$u+<@gvZ+e!EPJF&zY(MtfaKAn9-G>*hDl}R;^b|bIZoZRK@sX!TfgVLwpR2ut ztJ+WO^1TkmaALrd`cmy3qnSWJGnbj>$Yvp8)^SRHaA)!nl568b`$fwVUV4^|L@brvl)*Sel+I%n6%usm3 zfQA&xCp@R=u+KYU6quZvHPR2gmk)Wz^ZSFn=f}L~L+^PU-?;a@ezfCL^OyoI zd?^t4D8*sW)=wEW9_fQ#{Rtm)=Tl_>IyYPBm<^jwwkn@2eiSTIuH^jdsfBqSiol_+Sg0- z7Dh}$4nbm7tGTq8De~OsKLNnXf9Ut!zW7P?P~69iLml}v4z@0uv)HVP<{R~j)V_ty zq4u~{x;@06!e%wFn&m2WqDGyFuu-p42Wr%bWQWw$puQx8X6oJ7pOB91J0!DEnF*Eb zgOP?>b+Xm_=2VZ=fKx6OGUxc2Pfv_bnWjq9q$!5eD;79MdJpG>&1vjAY#zq}c>#GQ zb3o)|3}~EW8txEv8#R{}^$V7L+hT_|AV95muuX4T>rN~FJct~6&ejesV`WS zwH%g5aiZjQ;xWMrD;9Wc%(6s>$x20Z+n$o9^CVH4sKzh(vB%? zqtS9NjwuMCYuK{@cSPu5sOl$CQG`2J@4=zJBrb3lQfuq;jmuLR*8 z@CDDh4^yE)`FmM&KPehEp11I)r#!3Ff&oryypsF_AFoE-V_u)Ab6v{MN$~*X|Q>%_G z3_u+9Spt+`nTNR(BO5bvn1Jd2>OMRs`eVM%QY_-bF|zt3CGD8D{0~}5wTxCg8%ZaZ z!>c}h_PO1+ocvJ0^A`gh_abj%sh~zdHj321YW+JWe?#;{Fkae;kh$Fpg3#G$;8qf? zJ{v9<-H-|5p~daK>Ex(0w()X>D5PLVBQJ?DA(Ada0*XUBiWH$k(&3kEIIsw4fo4jq zc)<{?_@Q$&YeBM3Na#cqv?y8ea0=GRNT_6;l2H6;J9+?%l2w&ZH4-XW6B3$;f?kuX zTtayyRI*}j5YtLVL6;&~y~^x@4V}(CJ91WW`ShG1i$V=ncuLNvIYH zm8=;F%|t=pmaMZ9IvWXXzRt!clEjQDp}7;=-DXfie!CF zLSKu7O4f4{dhRHw-Z*RCYP4eg7yVlR literal 0 HcmV?d00001 diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT index 4723e5954dccb00995ccaf521b7daf6bf15cf1d4..b492f04b8866ae82eaded81aa0ea2d3a4969dc5c 100644 GIT binary patch delta 680 zcmaJ<&2G~`5S~pUV{JB)8yQg!6~4lu7y<|h3DvRPI3eqMM4y{^w5(@ zkbpZcz@aa|6VNj!j(G&ma3CkljIDBH52Np!ncZ)G_UEH{z#|>ya}R)h`@(;0l+IYp zHjN${6^?z|gqdC&Ug57k_MjzzPDO@|*h;Jfv(e8)n_Ry!yb}L-ucE|XAFcs3aR3fg z)umKCEvO@`VQ^7ZU;hv;0WKb&L9qxsBNbx-$vEn%RQZAb0Bp01jQrm5!O79-@&3UH zI&~iKZc}QH^AYnb&tlFQI5%e$9hkn=VW@=op6S~i-r}vA-KPktI+N=&>bY2yPdb~_ zxyoW)i;Lhpw;JJ4?Rv@4o7XQ-pZ`~XDVBnH*u-0v>6~?!f_ueW)C7&$a*B6@Q29Pd z1GvJ-Acyl%$pA`Z*bgzCgWEIl#Ait22^_j>X}68IWMw%{TC{<8$^B(7C3<(Aq*wz>$#JVB zZ9^zFki-aJD?onuP#{(uw6|5DbN+?q*kf)D&{MBHrYP)F)c4JBq!}s#;ysY_4d45| zc|&p@m-Ksn|3R5C>&@Dl*XosPuZ5nEK8rC%ZQ48S+;uj%>(`n?tB}cAgL?(h#-?Vw zzw~R@n$}-8qc5W9*2j^x9`uZ)`|kU-7F%m*uz%aFIK6?A`}=S4902FB zx3OP|DWE*mSfNyRXv5FacH}(RdBgeuN0tS8c{KN6N8x0*LkD95Q~z#J_EL%Ey|<6sK*f-x7SZ;97p?LO{`l??JyZ*53UL5xNRTfiE6jRsw z`w@4dQSq~#i0wp${rx>Qn)+;KoqfJuWdHu(*dE*C)0nMpuTXle)BYx#DsIuz510W4xLVY_=Z!y`I99b69?ewSwk_sY~}-da%2G7GyJcAc>A zXIQ4;10}%q4Bsa30>E|VRqLykSHq?gV$<-kaXP1;&#LNFd9Z!1+xIX4d5#M>r!?w$ zexhl`EM`t-iCIl+i*2z?{yjF>e(_4pKY(Ym?u3||1G$12v4~kDe^V=3`6DA>id46dhc3vomJND_)I=X85=? zkF$@n%wBRtng*pgpGw0s2YGOkj?I&KoIxHNdF-(5HJDo*VsFKp6ghvnX3^<%y#I(> zHSG4onJe$yohjsSRkF_Nl{%Ac3+)D*DN;YrAZV%}i=f43CUeF8eJnW=mqf$@a7rE% zJU~@QOyn2Xj9>zrM8s6k3=>R11rs4LF&cr*3Z@zXUDqP3fMz8VP!$qWRl)rvu_8}S zFcmZ>nQHI|b)92|&N0DM&@stWgGZ?A%o{rMf~lZ+Qzt@Q=eVJB+|W60>O`pPv<;oM zq0=^XBGh$a<O`pPN>FkYUi_P=q#E# z5$ZZ84V{yQ&Ph`zLS5&Sp>xX6Ic4fZsOy|IbWR&Or%jy*b)Al((=l{9rcQ*q&XS?C zWauoJIuYtRXAGS)hRzvNCqiB4tf6z(&^c@BM5ya@4V|u`(=~M>)ODUPbe=GDo-lPH z)OF4oI_C_XbEZy&y3Uh^&Xb1Dlcr9Dy3Tn+=e(hF-qeXu*Lg}XtI0}uN-%55Vs}b1 zy~B{0eu7;vm?DB7F*6dXLSiauFi?qA2C6~HKqXW#$v_ceG|E6FHi@XF@>()b2|X}S zgc!QO!ayZ9iHNBtmkd-w1(OUEq0$Khl~}=qfof1PPze=GGEjs{Ck#|#1rr9ULCHWR zR4~av5h|T9P>B^x7^ns%1C>z0Bm+gLbizO-Rxn|p8k7uFLIsly6rs`y1C?08gn?>M zGEfN>Ofpb}N+%3dVg(ZhszJ#>B~&oUKoKgPFi?pVOc2Z#2?Lc_!GwWoP%=;n6-+Wvgi0q2RAL1a2C6~HKqXW#$v_b*oiI>| z6-*eY1|DxEM;i4{y3s0Jkil~BPX14XEG!ayZfFkzq?lnhit1(OUE zq0$Khl~}=qfof1PPze=GGEjs{Ck#|#1rr9ULCHWRR4~av5h|T9P>B^x7^ns%1C>z0 zBm+gLbizO-Rxn|p8k7uFLIsly6rs`y14X16C?efJ5$XntP%}`C2?N!bWS|<83{+#n zKs6=|RAZ8XYD_XvjR^zQm@rU{Nd~Gh$v`zG3{+#nKs6>AsKz7%)tE3)MC$CqKoQ}L ziOD1bMTpa&LSm}9g@Gbca|;7Sq~?|k6rq}1GEjs*a~FoNP&O*=h(D`)^oMjePrK^i z-mjm}(!W%C??7)ktgw5v3dg-#qm4%!-)4B{a7pYna`<73#i<2##tno$db=;Dn_XB^K6RrO!I zh}Sgq63E7|d!;!(`{@*$$im$i)^CQD7}?xu`Hq8zfYDUl($H`B*ay_+cSX-My)|Kb zG$0Y59QL|B>;7gk1}abeN%dN)I$kUM=;}4CdQDWXVSIY^n)}1mYlH28w0o)QJo5zQ zJ*~Va%6qBu-ZAC9q`aRlkJoTNTD`B8_eFU>Ro*|Qyq}b>r_1M_pnP2`Ul--;sq*z> z%GZ{{-cmTKT3Z-%OQn9#g)Vly9ZWk3T{A zmR7zc%C}PGTgQ}d4Yun!TFO%8le=E69eApsw`}4CsM+V{#r>S5N#DMyGCDN#sZx*=MFnU*D-Tcq}=RM)sL$ z(${G!4W3bsq>+7Qn)LOSN`nWMBWYw`lEw+dmk{>_FAS;{KB{=(+Uh2Y;!=Uz4F4+V zw;pePvd%M1?6NG55arn3y1U?o@T^1DXe`28>)q@gbGaARFJ}fz{2%V+JXSxC;k!a_ zcoW}mVitYb7<(9fOtlhn#MVdrPQ=IA`y1BAZV}x#@d*NNPB-E^8y34UT6(avej~mi z1{kps-??F}_8Y&8tX*5|dG>bXte(@pJXFsGtx#S(li_Musa7sxdf%NCx5^HWLC4@H zbZmeB%ilbVh!ICYuihEW?gZ`Co)w7k#TEs-b0c>r=mxLIUYWFlcd>*y$RFRKZU)IK=Sz$H%*VL44<(aS zl1UPUyp{8uBmEGX(3}D{Y0hCl! z!^6|`^I)yl&m9515v zcPbURTV}2^tXIyn>+(LpednG+#|pdtd`^88qq~AGWkI|ki7&`qlI=wqy(D+PlDn$h z)#T2TJ3J3l`MTUS@HMxXlosDr=}TK}od5ZgNtVH1cRCrg!I!hg#m7a;3(|e=iQOuV1DwY+erYB)_nwZhh+4Zg_k* z?N@n0TH++7o#uA1 zeI@rCJ^qK?dQTZK$MXj*IbL|J+&Z$}94-HC@!O(Rh6X%#(`W2&i@ZFzR}=v)pqHG% zhbvx)6E1%ERu)wIY>$?2`fx^{aS`09=(N>k&!YOGLWusz*dPKdx}aD9f}YM=cdEnm!P literal 0 HcmV?d00001 From 6aa46d8ff1ee7e9ca0c4a54d75c74108bee22124 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:28:57 +0100 Subject: [PATCH 05/45] virtio: move VirtQueueElement at the beginning of the structs The next patch will make virtqueue_pop/vring_pop allocate memory for the VirtQueueElement. In some cases (blk, scsi, gpu) the device wants to extend VirtQueueElement with device-specific fields and, until now, the place of the VirtQueueElement within the containing struct didn't matter. When allocating the entire block in virtqueue_pop/vring_pop, however, the containing struct must basically be a "subclass" of VirtQueueElement, with the VirtQueueElement as the first field. Make that the case for blk and scsi; gpu is already doing it. Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/scsi/virtio-scsi.c | 3 +-- include/hw/virtio/virtio-blk.h | 2 +- include/hw/virtio/virtio-scsi.h | 13 ++++++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 1500c42728..7fdf6ade98 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -45,8 +45,7 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; - const size_t zero_skip = offsetof(VirtIOSCSIReq, elem) - + sizeof(VirtQueueElement); + const size_t zero_skip = offsetof(VirtIOSCSIReq, vring); req = g_malloc(sizeof(*req) + vs->cdb_size); req->vq = vq; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index ae11a63934..403ab86166 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -60,9 +60,9 @@ typedef struct VirtIOBlock { } VirtIOBlock; typedef struct VirtIOBlockReq { + VirtQueueElement elem; int64_t sector_num; VirtIOBlock *dev; - VirtQueueElement elem; struct virtio_blk_inhdr *in; struct virtio_blk_outhdr out; QEMUIOVector qiov; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 0394eb23de..eb9d25b9fb 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -112,18 +112,17 @@ typedef struct VirtIOSCSI { } VirtIOSCSI; typedef struct VirtIOSCSIReq { + /* Note: + * - fields up to resp_iov are initialized by virtio_scsi_init_req; + * - fields starting at vring are zeroed by virtio_scsi_init_req. + * */ + VirtQueueElement elem; + VirtIOSCSI *dev; VirtQueue *vq; QEMUSGList qsgl; QEMUIOVector resp_iov; - /* Note: - * - fields before elem are initialized by virtio_scsi_init_req; - * - elem is uninitialized at the time of allocation. - * - fields after elem are zeroed by virtio_scsi_init_req. - * */ - - VirtQueueElement elem; /* Set by dataplane code. */ VirtIOSCSIVring *vring; From 51b19ebe4320f3dcd93cea71235c1219318ddfd2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Feb 2016 16:26:51 +0200 Subject: [PATCH 06/45] virtio: move allocation to virtqueue_pop/vring_pop The return code of virtqueue_pop/vring_pop is unused except to check for errors or 0. We can thus easily move allocation inside the functions and just return a pointer to the VirtQueueElement. The advantage is that we will be able to allocate only the space that is needed for the actual size of the s/g list instead of the full VIRTQUEUE_MAX_SIZE items. Currently VirtQueueElement takes about 48K of memory, and this kind of allocation puts a lot of stress on malloc. By cutting the size by two or three orders of magnitude, malloc can use much more efficient algorithms. The patch is pretty large, but changes to each device are testable more or less independently. Splitting it would mostly add churn. Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/9pfs/9p.c | 2 +- hw/9pfs/virtio-9p-device.c | 17 +++--- hw/9pfs/virtio-9p.h | 2 +- hw/block/dataplane/virtio-blk.c | 11 ++-- hw/block/virtio-blk.c | 15 +++--- hw/char/virtio-serial-bus.c | 80 ++++++++++++++++++----------- hw/display/virtio-gpu.c | 21 +++++--- hw/input/virtio-input.c | 24 ++++++--- hw/net/virtio-net.c | 69 +++++++++++++++---------- hw/scsi/virtio-scsi-dataplane.c | 15 +++--- hw/scsi/virtio-scsi.c | 18 +++---- hw/virtio/dataplane/vring.c | 18 ++++--- hw/virtio/virtio-balloon.c | 22 +++++--- hw/virtio/virtio-rng.c | 10 ++-- hw/virtio/virtio.c | 12 +++-- include/hw/virtio/dataplane/vring.h | 2 +- include/hw/virtio/virtio-balloon.h | 2 +- include/hw/virtio/virtio-blk.h | 3 +- include/hw/virtio/virtio-net.h | 2 +- include/hw/virtio/virtio-scsi.h | 2 +- include/hw/virtio/virtio-serial.h | 2 +- include/hw/virtio/virtio.h | 2 +- 22 files changed, 209 insertions(+), 142 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 15fb0ab75d..db5f4780dc 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1587,7 +1587,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, int read_count; int64_t xattr_len; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem = v->elems[pdu->idx]; xattr_len = fidp->fs.xattr.len; read_count = xattr_len - off; diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index c5f7b92640..a38850ee89 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -26,10 +26,12 @@ void virtio_9p_push_and_notify(V9fsPDU *pdu) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem = v->elems[pdu->idx]; /* push onto queue and notify */ virtqueue_push(v->vq, elem, pdu->size); + g_free(elem); + v->elems[pdu->idx] = NULL; /* FIXME: we should batch these completions */ virtio_notify(VIRTIO_DEVICE(v), v->vq); @@ -48,10 +50,10 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) uint8_t id; uint16_t tag_le; } QEMU_PACKED out; - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem; - len = virtqueue_pop(vq, elem); - if (!len) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { pdu_free(pdu); break; } @@ -59,6 +61,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) BUG_ON(elem->out_num == 0 || elem->in_num == 0); QEMU_BUILD_BUG_ON(sizeof out != 7); + v->elems[pdu->idx] = elem; len = iov_to_buf(elem->out_sg, elem->out_num, 0, &out, sizeof out); BUG_ON(len != sizeof out); @@ -141,7 +144,7 @@ ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem = v->elems[pdu->idx]; return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap); } @@ -151,7 +154,7 @@ ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem = v->elems[pdu->idx]; return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap); } @@ -161,7 +164,7 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = &v->elems[pdu->idx]; + VirtQueueElement *elem = v->elems[pdu->idx]; if (is_write) { *piov = elem->out_sg; diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 1cdf0a2d65..7f6d885539 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -11,7 +11,7 @@ typedef struct V9fsVirtioState VirtQueue *vq; size_t config_size; V9fsPDU pdus[MAX_REQ]; - VirtQueueElement elems[MAX_REQ]; + VirtQueueElement *elems[MAX_REQ]; V9fsState state; } V9fsVirtioState; diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index ee0c4d4070..0d9978109c 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -100,20 +100,19 @@ static void handle_notify(EventNotifier *e) blk_io_plug(s->conf->conf.blk); for (;;) { MultiReqBuffer mrb = {}; - int ret; /* Disable guest->host notifies to avoid unnecessary vmexits */ vring_disable_notification(s->vdev, &s->vring); for (;;) { - VirtIOBlockReq *req = virtio_blk_alloc_request(vblk); + VirtIOBlockReq *req = vring_pop(s->vdev, &s->vring, + sizeof(VirtIOBlockReq)); - ret = vring_pop(s->vdev, &s->vring, &req->elem); - if (ret < 0) { - virtio_blk_free_request(req); + if (req == NULL) { break; /* no more requests */ } + virtio_blk_init_request(vblk, req); trace_virtio_blk_data_plane_process_request(s, req->elem.out_num, req->elem.in_num, req->elem.index); @@ -125,7 +124,7 @@ static void handle_notify(EventNotifier *e) virtio_blk_submit_multireq(s->conf->conf.blk, &mrb); } - if (likely(ret == -EAGAIN)) { /* vring emptied */ + if (likely(!vring_more_avail(s->vdev, &s->vring))) { /* vring emptied */ /* Re-enable guest->host notifies and stop processing the vring. * But if the guest has snuck in more descriptors, keep processing. */ diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 11bedff6d6..bf70b52dfd 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -29,15 +29,13 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s) +void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req) { - VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1); req->dev = s; req->qiov.size = 0; req->in_len = 0; req->next = NULL; req->mr_next = NULL; - return req; } void virtio_blk_free_request(VirtIOBlockReq *req) @@ -193,13 +191,11 @@ out: static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) { - VirtIOBlockReq *req = virtio_blk_alloc_request(s); + VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq)); - if (!virtqueue_pop(s->vq, &req->elem)) { - virtio_blk_free_request(req); - return NULL; + if (req) { + virtio_blk_init_request(s, req); } - return req; } @@ -836,7 +832,8 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { - VirtIOBlockReq *req = virtio_blk_alloc_request(s); + VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1); + virtio_blk_init_request(s, req); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(VirtQueueElement)); req->next = s->rq; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 8d5c740558..cf3d12b9d5 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -83,7 +83,7 @@ static bool use_multiport(VirtIOSerial *vser) static size_t write_to_port(VirtIOSerialPort *port, const uint8_t *buf, size_t size) { - VirtQueueElement elem; + VirtQueueElement *elem; VirtQueue *vq; size_t offset; @@ -96,15 +96,17 @@ static size_t write_to_port(VirtIOSerialPort *port, while (offset < size) { size_t len; - if (!virtqueue_pop(vq, &elem)) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { break; } - len = iov_from_buf(elem.in_sg, elem.in_num, 0, + len = iov_from_buf(elem->in_sg, elem->in_num, 0, buf + offset, size - offset); offset += len; - virtqueue_push(vq, &elem, len); + virtqueue_push(vq, elem, len); + g_free(elem); } virtio_notify(VIRTIO_DEVICE(port->vser), vq); @@ -113,13 +115,18 @@ static size_t write_to_port(VirtIOSerialPort *port, static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) { - VirtQueueElement elem; + VirtQueueElement *elem; if (!virtio_queue_ready(vq)) { return; } - while (virtqueue_pop(vq, &elem)) { - virtqueue_push(vq, &elem, 0); + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + virtqueue_push(vq, elem, 0); + g_free(elem); } virtio_notify(vdev, vq); } @@ -138,21 +145,22 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, unsigned int i; /* Pop an elem only if we haven't left off a previous one mid-way */ - if (!port->elem.out_num) { - if (!virtqueue_pop(vq, &port->elem)) { + if (!port->elem) { + port->elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!port->elem) { break; } port->iov_idx = 0; port->iov_offset = 0; } - for (i = port->iov_idx; i < port->elem.out_num; i++) { + for (i = port->iov_idx; i < port->elem->out_num; i++) { size_t buf_size; ssize_t ret; - buf_size = port->elem.out_sg[i].iov_len - port->iov_offset; + buf_size = port->elem->out_sg[i].iov_len - port->iov_offset; ret = vsc->have_data(port, - port->elem.out_sg[i].iov_base + port->elem->out_sg[i].iov_base + port->iov_offset, buf_size); if (port->throttled) { @@ -167,8 +175,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, if (port->throttled) { break; } - virtqueue_push(vq, &port->elem, 0); - port->elem.out_num = 0; + virtqueue_push(vq, port->elem, 0); + g_free(port->elem); + port->elem = NULL; } virtio_notify(vdev, vq); } @@ -185,22 +194,26 @@ static void flush_queued_data(VirtIOSerialPort *port) static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len) { - VirtQueueElement elem; + VirtQueueElement *elem; VirtQueue *vq; vq = vser->c_ivq; if (!virtio_queue_ready(vq)) { return 0; } - if (!virtqueue_pop(vq, &elem)) { + + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { return 0; } /* TODO: detect a buffer that's too short, set NEEDS_RESET */ - iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len); + iov_from_buf(elem->in_sg, elem->in_num, 0, buf, len); - virtqueue_push(vq, &elem, len); + virtqueue_push(vq, elem, len); virtio_notify(VIRTIO_DEVICE(vser), vq); + g_free(elem); + return len; } @@ -414,7 +427,7 @@ static void control_in(VirtIODevice *vdev, VirtQueue *vq) static void control_out(VirtIODevice *vdev, VirtQueue *vq) { - VirtQueueElement elem; + VirtQueueElement *elem; VirtIOSerial *vser; uint8_t *buf; size_t len; @@ -423,10 +436,15 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq) len = 0; buf = NULL; - while (virtqueue_pop(vq, &elem)) { + for (;;) { size_t cur_len; - cur_len = iov_size(elem.out_sg, elem.out_num); + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + + cur_len = iov_size(elem->out_sg, elem->out_num); /* * Allocate a new buf only if we didn't have one previously or * if the size of the buf differs @@ -437,10 +455,11 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq) buf = g_malloc(cur_len); len = cur_len; } - iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len); + iov_to_buf(elem->out_sg, elem->out_num, 0, buf, cur_len); handle_control_message(vser, buf, cur_len); - virtqueue_push(vq, &elem, 0); + virtqueue_push(vq, elem, 0); + g_free(elem); } g_free(buf); virtio_notify(vdev, vq); @@ -620,7 +639,7 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_byte(f, port->host_connected); elem_popped = 0; - if (port->elem.out_num) { + if (port->elem) { elem_popped = 1; } qemu_put_be32s(f, &elem_popped); @@ -628,8 +647,8 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_be32s(f, &port->iov_idx); qemu_put_be64s(f, &port->iov_offset); - qemu_put_buffer(f, (unsigned char *)&port->elem, - sizeof(port->elem)); + qemu_put_buffer(f, (unsigned char *)port->elem, + sizeof(VirtQueueElement)); } } } @@ -704,9 +723,10 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id, qemu_get_be32s(f, &port->iov_idx); qemu_get_be64s(f, &port->iov_offset); - qemu_get_buffer(f, (unsigned char *)&port->elem, - sizeof(port->elem)); - virtqueue_map(&port->elem); + port->elem = g_new(VirtQueueElement, 1); + qemu_get_buffer(f, (unsigned char *)port->elem, + sizeof(VirtQueueElement)); + virtqueue_map(port->elem); /* * Port was throttled on source machine. Let's @@ -928,7 +948,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) return; } - port->elem.out_num = 0; + port->elem = NULL; } static void virtser_port_device_plug(HotplugHandler *hotplug_dev, diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1cb4002e0e..ddf3bfbef4 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -804,16 +804,15 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } #endif - cmd = g_new(struct virtio_gpu_ctrl_command, 1); - while (virtqueue_pop(vq, &cmd->elem)) { + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + while (cmd) { cmd->vq = vq; cmd->error = 0; cmd->finished = false; cmd->waiting = false; QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); - cmd = g_new(struct virtio_gpu_ctrl_command, 1); + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } - g_free(cmd); virtio_gpu_process_cmdq(g); @@ -833,15 +832,20 @@ static void virtio_gpu_ctrl_bh(void *opaque) static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); - VirtQueueElement elem; + VirtQueueElement *elem; size_t s; struct virtio_gpu_update_cursor cursor_info; if (!virtio_queue_ready(vq)) { return; } - while (virtqueue_pop(vq, &elem)) { - s = iov_to_buf(elem.out_sg, elem.out_num, 0, + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + + s = iov_to_buf(elem->out_sg, elem->out_num, 0, &cursor_info, sizeof(cursor_info)); if (s != sizeof(cursor_info)) { qemu_log_mask(LOG_GUEST_ERROR, @@ -850,8 +854,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) } else { update_cursor(g, &cursor_info); } - virtqueue_push(vq, &elem, 0); + virtqueue_push(vq, elem, 0); virtio_notify(vdev, vq); + g_free(elem); } } diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index f12ed8a504..5061f4cf7a 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -17,7 +17,7 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) { - VirtQueueElement elem; + VirtQueueElement *elem; unsigned have, need; int i, len; @@ -50,14 +50,16 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) /* ... and finally pass them to the guest */ for (i = 0; i < vinput->qindex; i++) { - if (!virtqueue_pop(vinput->evt, &elem)) { + elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement)); + if (!elem) { /* should not happen, we've checked for space beforehand */ fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__); return; } - len = iov_from_buf(elem.in_sg, elem.in_num, + len = iov_from_buf(elem->in_sg, elem->in_num, 0, vinput->queue+i, sizeof(virtio_input_event)); - virtqueue_push(vinput->evt, &elem, len); + virtqueue_push(vinput->evt, elem, len); + g_free(elem); } virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt); vinput->qindex = 0; @@ -73,17 +75,23 @@ static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq) VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev); VirtIOInput *vinput = VIRTIO_INPUT(vdev); virtio_input_event event; - VirtQueueElement elem; + VirtQueueElement *elem; int len; - while (virtqueue_pop(vinput->sts, &elem)) { + for (;;) { + elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + memset(&event, 0, sizeof(event)); - len = iov_to_buf(elem.out_sg, elem.out_num, + len = iov_to_buf(elem->out_sg, elem->out_num, 0, &event, sizeof(event)); if (vic->handle_status) { vic->handle_status(vinput, &event); } - virtqueue_push(vinput->sts, &elem, len); + virtqueue_push(vinput->sts, elem, len); + g_free(elem); } virtio_notify(vdev, vinput->sts); } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index fde8dd3157..de696e8dd0 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -819,20 +819,24 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_ctrl_hdr ctrl; virtio_net_ctrl_ack status = VIRTIO_NET_ERR; - VirtQueueElement elem; + VirtQueueElement *elem; size_t s; struct iovec *iov, *iov2; unsigned int iov_cnt; - while (virtqueue_pop(vq, &elem)) { - if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) || - iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) { + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || + iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { error_report("virtio-net ctrl missing headers"); exit(1); } - iov_cnt = elem.out_num; - iov2 = iov = g_memdup(elem.out_sg, sizeof(struct iovec) * elem.out_num); + iov_cnt = elem->out_num; + iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); if (s != sizeof(ctrl)) { @@ -851,12 +855,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); } - s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status)); + s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); assert(s == sizeof(status)); - virtqueue_push(vq, &elem, sizeof(status)); + virtqueue_push(vq, elem, sizeof(status)); virtio_notify(vdev, vq); g_free(iov2); + g_free(elem); } } @@ -1045,13 +1050,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t offset = i = 0; while (offset < size) { - VirtQueueElement elem; + VirtQueueElement *elem; int len, total; - const struct iovec *sg = elem.in_sg; + const struct iovec *sg; total = 0; - if (virtqueue_pop(q->rx_vq, &elem) == 0) { + elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); + if (!elem) { if (i == 0) return -1; error_report("virtio-net unexpected empty queue: " @@ -1064,21 +1070,22 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t exit(1); } - if (elem.in_num < 1) { + if (elem->in_num < 1) { error_report("virtio-net receive queue contains no in buffers"); exit(1); } + sg = elem->in_sg; if (i == 0) { assert(offset == 0); if (n->mergeable_rx_bufs) { mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), - sg, elem.in_num, + sg, elem->in_num, offsetof(typeof(mhdr), num_buffers), sizeof(mhdr.num_buffers)); } - receive_header(n, sg, elem.in_num, buf, size); + receive_header(n, sg, elem->in_num, buf, size); offset = n->host_hdr_len; total += n->guest_hdr_len; guest_offset = n->guest_hdr_len; @@ -1087,7 +1094,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t } /* copy in packet. ugh */ - len = iov_from_buf(sg, elem.in_num, guest_offset, + len = iov_from_buf(sg, elem->in_num, guest_offset, buf + offset, size - offset); total += len; offset += len; @@ -1095,12 +1102,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t * must have consumed the complete packet. * Otherwise, drop it. */ if (!n->mergeable_rx_bufs && offset < size) { - virtqueue_discard(q->rx_vq, &elem, total); + virtqueue_discard(q->rx_vq, elem, total); + g_free(elem); return size; } /* signal other side */ - virtqueue_fill(q->rx_vq, &elem, total, i++); + virtqueue_fill(q->rx_vq, elem, total, i++); + g_free(elem); } if (mhdr_cnt) { @@ -1124,10 +1133,11 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) VirtIONetQueue *q = virtio_net_get_subqueue(nc); VirtIODevice *vdev = VIRTIO_DEVICE(n); - virtqueue_push(q->tx_vq, &q->async_tx.elem, 0); + virtqueue_push(q->tx_vq, q->async_tx.elem, 0); virtio_notify(vdev, q->tx_vq); - q->async_tx.elem.out_num = 0; + g_free(q->async_tx.elem); + q->async_tx.elem = NULL; virtio_queue_set_notification(q->tx_vq, 1); virtio_net_flush_tx(q); @@ -1138,25 +1148,31 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) { VirtIONet *n = q->n; VirtIODevice *vdev = VIRTIO_DEVICE(n); - VirtQueueElement elem; + VirtQueueElement *elem; int32_t num_packets = 0; int queue_index = vq2q(virtio_get_queue_index(q->tx_vq)); if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { return num_packets; } - if (q->async_tx.elem.out_num) { + if (q->async_tx.elem) { virtio_queue_set_notification(q->tx_vq, 0); return num_packets; } - while (virtqueue_pop(q->tx_vq, &elem)) { + for (;;) { ssize_t ret; - unsigned int out_num = elem.out_num; - struct iovec *out_sg = &elem.out_sg[0]; - struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1]; + unsigned int out_num; + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; struct virtio_net_hdr_mrg_rxbuf mhdr; + elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + + out_num = elem->out_num; + out_sg = elem->out_sg; if (out_num < 1) { error_report("virtio-net header not in first element"); exit(1); @@ -1208,8 +1224,9 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) } drop: - virtqueue_push(q->tx_vq, &elem, 0); + virtqueue_push(q->tx_vq, elem, 0); virtio_notify(vdev, q->tx_vq); + g_free(elem); if (++num_packets >= n->tx_burst) { break; diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index c77b3a1058..8340326a50 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -81,15 +81,16 @@ fail_vring: VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, VirtIOSCSIVring *vring) { - VirtIOSCSIReq *req = virtio_scsi_init_req(s, NULL); - int r; + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; + VirtIOSCSIReq *req; - req->vring = vring; - r = vring_pop((VirtIODevice *)s, &vring->vring, &req->elem); - if (r < 0) { - virtio_scsi_free_req(req); - req = NULL; + req = vring_pop((VirtIODevice *)s, &vring->vring, + sizeof(VirtIOSCSIReq) + vs->cdb_size); + if (!req) { + return NULL; } + virtio_scsi_init_req(s, NULL, req); + req->vring = vring; return req; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 7fdf6ade98..50a3cb28b5 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -41,19 +41,15 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } -VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) +void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req) { - VirtIOSCSIReq *req; - VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; const size_t zero_skip = offsetof(VirtIOSCSIReq, vring); - req = g_malloc(sizeof(*req) + vs->cdb_size); req->vq = vq; req->dev = s; qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory); qemu_iovec_init(&req->resp_iov, 1); memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip); - return req; } void virtio_scsi_free_req(VirtIOSCSIReq *req) @@ -174,11 +170,14 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) { - VirtIOSCSIReq *req = virtio_scsi_init_req(s, vq); - if (!virtqueue_pop(vq, &req->elem)) { - virtio_scsi_free_req(req); + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; + VirtIOSCSIReq *req; + + req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size); + if (!req) { return NULL; } + virtio_scsi_init_req(s, vq, req); return req; } @@ -203,8 +202,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); - req = virtio_scsi_init_req(s, vs->cmd_vqs[n]); + req = g_malloc(sizeof(VirtIOSCSIReq) + vs->cdb_size); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + virtio_scsi_init_req(s, vs->cmd_vqs[n], req); virtqueue_map(&req->elem); diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 1a78df10fa..4fb84bb00a 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -389,23 +389,26 @@ static void vring_unmap_element(VirtQueueElement *elem) * * Stolen from linux/drivers/vhost/vhost.c. */ -int vring_pop(VirtIODevice *vdev, Vring *vring, - VirtQueueElement *elem) +void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) { struct vring_desc desc; unsigned int i, head, found = 0, num = vring->vr.num; uint16_t avail_idx, last_avail_idx; + VirtQueueElement *elem = NULL; int ret; - /* Initialize elem so it can be safely unmapped */ - elem->in_num = elem->out_num = 0; - /* If there was a fatal error then refuse operation */ if (vring->broken) { ret = -EFAULT; goto out; } + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); + + /* Initialize elem so it can be safely unmapped */ + elem->in_num = elem->out_num = 0; + /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vring->last_avail_idx; avail_idx = vring_get_avail_idx(vdev, vring); @@ -481,7 +484,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, virtio_tswap16(vdev, vring->last_avail_idx); } - return head; + return elem; out: assert(ret < 0); @@ -489,7 +492,8 @@ out: vring->broken = true; } vring_unmap_element(elem); - return ret; + g_free(elem); + return NULL; } /* After we've used one of their buffers, we tell them about it. diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index f5f25a95fc..5c3020331c 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -107,8 +107,10 @@ static void balloon_stats_poll_cb(void *opaque) return; } - virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset); + virtqueue_push(s->svq, s->stats_vq_elem, s->stats_vq_offset); virtio_notify(vdev, s->svq); + g_free(s->stats_vq_elem); + s->stats_vq_elem = NULL; } static void balloon_stats_get_all(Object *obj, struct Visitor *v, @@ -206,14 +208,18 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); - VirtQueueElement elem; + VirtQueueElement *elem; MemoryRegionSection section; - while (virtqueue_pop(vq, &elem)) { + for (;;) { size_t offset = 0; uint32_t pfn; + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + return; + } - while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) { + while (iov_to_buf(elem->out_sg, elem->out_num, offset, &pfn, 4) == 4) { ram_addr_t pa; ram_addr_t addr; int p = virtio_ldl_p(vdev, &pfn); @@ -236,20 +242,22 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) memory_region_unref(section.mr); } - virtqueue_push(vq, &elem, offset); + virtqueue_push(vq, elem, offset); virtio_notify(vdev, vq); + g_free(elem); } } static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); - VirtQueueElement *elem = &s->stats_vq_elem; + VirtQueueElement *elem; VirtIOBalloonStat stat; size_t offset = 0; qemu_timeval tv; - if (!virtqueue_pop(vq, elem)) { + s->stats_vq_elem = elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { goto out; } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index a80fb89069..17da2f8f3d 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -44,7 +44,7 @@ static void chr_read(void *opaque, const void *buf, size_t size) { VirtIORNG *vrng = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(vrng); - VirtQueueElement elem; + VirtQueueElement *elem; size_t len; int offset; @@ -56,15 +56,17 @@ static void chr_read(void *opaque, const void *buf, size_t size) offset = 0; while (offset < size) { - if (!virtqueue_pop(vrng->vq, &elem)) { + elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement)); + if (!elem) { break; } - len = iov_from_buf(elem.in_sg, elem.in_num, + len = iov_from_buf(elem->in_sg, elem->in_num, 0, buf + offset, size - offset); offset += len; - virtqueue_push(vrng->vq, &elem, len); + virtqueue_push(vrng->vq, elem, len); trace_virtio_rng_pushed(vrng, len); + g_free(elem); } virtio_notify(vdev, vrng->vq); } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 0603793e34..229a092c83 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -501,16 +501,20 @@ void virtqueue_map(VirtQueueElement *elem) 0); } -int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) +void *virtqueue_pop(VirtQueue *vq, size_t sz) { unsigned int i, head, max; hwaddr desc_pa = vq->vring.desc; VirtIODevice *vdev = vq->vdev; + VirtQueueElement *elem; - if (!virtqueue_num_heads(vq, vq->last_avail_idx)) - return 0; + if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { + return NULL; + } /* When we start there are none of either input nor output. */ + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); elem->out_num = elem->in_num = 0; max = vq->vring.num; @@ -569,7 +573,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) vq->inuse++; trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); - return elem->in_num + elem->out_num; + return elem; } /* virtio device */ diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h index a596e4c175..e80985ee4c 100644 --- a/include/hw/virtio/dataplane/vring.h +++ b/include/hw/virtio/dataplane/vring.h @@ -44,7 +44,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n); void vring_disable_notification(VirtIODevice *vdev, Vring *vring); bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); bool vring_should_notify(VirtIODevice *vdev, Vring *vring); -int vring_pop(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem); +void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz); void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, int len); diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index 09c2ce4dcd..35f62ac119 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -37,7 +37,7 @@ typedef struct VirtIOBalloon { uint32_t num_pages; uint32_t actual; uint64_t stats[VIRTIO_BALLOON_S_NR]; - VirtQueueElement stats_vq_elem; + VirtQueueElement *stats_vq_elem; size_t stats_vq_offset; QEMUTimer *stats_timer; int64_t stats_last_update; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 403ab86166..199bb0ebd5 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -80,8 +80,7 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s); - +void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req); void virtio_blk_free_request(VirtIOBlockReq *req); void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index f3cc25feca..2ce3b03bd4 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -47,7 +47,7 @@ typedef struct VirtIONetQueue { QEMUBH *tx_bh; int tx_waiting; struct { - VirtQueueElement elem; + VirtQueueElement *elem; } async_tx; struct VirtIONet *n; } VirtIONetQueue; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index eb9d25b9fb..a8029aa017 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -160,7 +160,7 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req); -VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason); diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h index 527d0bf624..12a55a19e9 100644 --- a/include/hw/virtio/virtio-serial.h +++ b/include/hw/virtio/virtio-serial.h @@ -122,7 +122,7 @@ struct VirtIOSerialPort { * element popped and continue consuming it once the backend * becomes writable again. */ - VirtQueueElement elem; + VirtQueueElement *elem; /* * The index and the offset into the iov buffer that was popped in diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 205fadf234..21fda17807 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -152,7 +152,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); void virtqueue_map(VirtQueueElement *elem); -int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); +void *virtqueue_pop(VirtQueue *vq, size_t sz); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, From ab281c1781add112a257c15924d670616a99c41a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:28:59 +0100 Subject: [PATCH 07/45] virtio: introduce qemu_get/put_virtqueue_element Move allocation to virtio functions also when loading/saving a VirtQueueElement. This will also let the load/save functions keep backwards compatibility when the VirtQueueElement layout is changed. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 10 +++------- hw/char/virtio-serial-bus.c | 10 +++------- hw/scsi/virtio-scsi.c | 7 ++----- hw/virtio/virtio.c | 13 +++++++++++++ include/hw/virtio/virtio.h | 2 ++ 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index bf70b52dfd..c427698fcb 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -808,8 +808,7 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) while (req) { qemu_put_sbyte(f, 1); - qemu_put_buffer(f, (unsigned char *)&req->elem, - sizeof(VirtQueueElement)); + qemu_put_virtqueue_element(f, &req->elem); req = req->next; } qemu_put_sbyte(f, 0); @@ -832,14 +831,11 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { - VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1); + VirtIOBlockReq *req; + req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); virtio_blk_init_request(s, req); - qemu_get_buffer(f, (unsigned char *)&req->elem, - sizeof(VirtQueueElement)); req->next = s->rq; s->rq = req; - - virtqueue_map(&req->elem); } return 0; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index cf3d12b9d5..99cb6836ad 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -646,9 +646,7 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) if (elem_popped) { qemu_put_be32s(f, &port->iov_idx); qemu_put_be64s(f, &port->iov_offset); - - qemu_put_buffer(f, (unsigned char *)port->elem, - sizeof(VirtQueueElement)); + qemu_put_virtqueue_element(f, port->elem); } } } @@ -723,10 +721,8 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id, qemu_get_be32s(f, &port->iov_idx); qemu_get_be64s(f, &port->iov_offset); - port->elem = g_new(VirtQueueElement, 1); - qemu_get_buffer(f, (unsigned char *)port->elem, - sizeof(VirtQueueElement)); - virtqueue_map(port->elem); + port->elem = + qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); /* * Port was throttled on source machine. Let's diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 50a3cb28b5..5b29baccf3 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -189,7 +189,7 @@ static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) assert(n < vs->conf.num_queues); qemu_put_be32s(f, &n); - qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + qemu_put_virtqueue_element(f, &req->elem); } static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) @@ -202,12 +202,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); - req = g_malloc(sizeof(VirtIOSCSIReq) + vs->cdb_size); - qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size); virtio_scsi_init_req(s, vs->cmd_vqs[n], req); - virtqueue_map(&req->elem); - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) { error_report("invalid SCSI request migration data"); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 229a092c83..28fa7fe760 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -576,6 +576,19 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) return elem; } +void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz) +{ + VirtQueueElement *elem = g_malloc(sz); + qemu_get_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + virtqueue_map(elem); + return elem; +} + +void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem) +{ + qemu_put_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); +} + /* virtio device */ static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 21fda17807..44da9a8433 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -153,6 +153,8 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, void virtqueue_map(VirtQueueElement *elem); void *virtqueue_pop(VirtQueue *vq, size_t sz); +void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz); +void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, From 3724650db07057333879484c8bc7d900b5c1bf8e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:29:00 +0100 Subject: [PATCH 08/45] virtio: introduce virtqueue_alloc_element Allocate the arrays for in_addr/out_addr/in_sg/out_sg outside the VirtQueueElement. For now, virtqueue_pop and vring_pop keep allocating a very large VirtQueueElement. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/dataplane/vring.c | 3 +- hw/virtio/virtio.c | 110 ++++++++++++++++++++++++++++++++---- include/hw/virtio/virtio.h | 9 +-- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 4fb84bb00a..57ada3bcbe 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -403,8 +403,7 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) goto out; } - assert(sz >= sizeof(VirtQueueElement)); - elem = g_malloc(sz); + elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); /* Initialize elem so it can be safely unmapped */ elem->in_num = elem->out_num = 0; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 28fa7fe760..661a1e1536 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -494,11 +494,30 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, void virtqueue_map(VirtQueueElement *elem) { virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num, - MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)), - 1); + VIRTQUEUE_MAX_SIZE, 1); virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num, - MIN(ARRAY_SIZE(elem->out_sg), ARRAY_SIZE(elem->out_addr)), - 0); + VIRTQUEUE_MAX_SIZE, 0); +} + +void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num) +{ + VirtQueueElement *elem; + size_t in_addr_ofs = QEMU_ALIGN_UP(sz, __alignof__(elem->in_addr[0])); + size_t out_addr_ofs = in_addr_ofs + in_num * sizeof(elem->in_addr[0]); + size_t out_addr_end = out_addr_ofs + out_num * sizeof(elem->out_addr[0]); + size_t in_sg_ofs = QEMU_ALIGN_UP(out_addr_end, __alignof__(elem->in_sg[0])); + size_t out_sg_ofs = in_sg_ofs + in_num * sizeof(elem->in_sg[0]); + size_t out_sg_end = out_sg_ofs + out_num * sizeof(elem->out_sg[0]); + + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(out_sg_end); + elem->out_num = out_num; + elem->in_num = in_num; + elem->in_addr = (void *)elem + in_addr_ofs; + elem->out_addr = (void *)elem + out_addr_ofs; + elem->in_sg = (void *)elem + in_sg_ofs; + elem->out_sg = (void *)elem + out_sg_ofs; + return elem; } void *virtqueue_pop(VirtQueue *vq, size_t sz) @@ -513,8 +532,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) } /* When we start there are none of either input nor output. */ - assert(sz >= sizeof(VirtQueueElement)); - elem = g_malloc(sz); + elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); elem->out_num = elem->in_num = 0; max = vq->vring.num; @@ -541,14 +559,14 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) struct iovec *sg; if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { - if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) { + if (elem->in_num >= VIRTQUEUE_MAX_SIZE) { error_report("Too many write descriptors in indirect table"); exit(1); } elem->in_addr[elem->in_num] = vring_desc_addr(vdev, desc_pa, i); sg = &elem->in_sg[elem->in_num++]; } else { - if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) { + if (elem->out_num >= VIRTQUEUE_MAX_SIZE) { error_report("Too many read descriptors in indirect table"); exit(1); } @@ -576,17 +594,87 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) return elem; } +/* Reading and writing a structure directly to QEMUFile is *awful*, but + * it is what QEMU has always done by mistake. We can change it sooner + * or later by bumping the version number of the affected vm states. + * In the meanwhile, since the in-memory layout of VirtQueueElement + * has changed, we need to marshal to and from the layout that was + * used before the change. + */ +typedef struct VirtQueueElementOld { + unsigned int index; + unsigned int out_num; + unsigned int in_num; + hwaddr in_addr[VIRTQUEUE_MAX_SIZE]; + hwaddr out_addr[VIRTQUEUE_MAX_SIZE]; + struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; + struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; +} VirtQueueElementOld; + void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz) { - VirtQueueElement *elem = g_malloc(sz); - qemu_get_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + VirtQueueElement *elem; + VirtQueueElementOld data; + int i; + + qemu_get_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld)); + + elem = virtqueue_alloc_element(sz, data.out_num, data.in_num); + elem->index = data.index; + + for (i = 0; i < elem->in_num; i++) { + elem->in_addr[i] = data.in_addr[i]; + } + + for (i = 0; i < elem->out_num; i++) { + elem->out_addr[i] = data.out_addr[i]; + } + + for (i = 0; i < elem->in_num; i++) { + /* Base is overwritten by virtqueue_map. */ + elem->in_sg[i].iov_base = 0; + elem->in_sg[i].iov_len = data.in_sg[i].iov_len; + } + + for (i = 0; i < elem->out_num; i++) { + /* Base is overwritten by virtqueue_map. */ + elem->out_sg[i].iov_base = 0; + elem->out_sg[i].iov_len = data.out_sg[i].iov_len; + } + virtqueue_map(elem); return elem; } void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem) { - qemu_put_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + VirtQueueElementOld data; + int i; + + memset(&data, 0, sizeof(data)); + data.index = elem->index; + data.in_num = elem->in_num; + data.out_num = elem->out_num; + + for (i = 0; i < elem->in_num; i++) { + data.in_addr[i] = elem->in_addr[i]; + } + + for (i = 0; i < elem->out_num; i++) { + data.out_addr[i] = elem->out_addr[i]; + } + + for (i = 0; i < elem->in_num; i++) { + /* Base is overwritten by virtqueue_map when loading. Do not + * save it, as it would leak the QEMU address space layout. */ + data.in_sg[i].iov_len = elem->in_sg[i].iov_len; + } + + for (i = 0; i < elem->out_num; i++) { + /* Do not save iov_base as above. */ + data.out_sg[i].iov_len = elem->out_sg[i].iov_len; + } + qemu_put_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld)); } /* virtio device */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 44da9a8433..108cdb0f48 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -46,10 +46,10 @@ typedef struct VirtQueueElement unsigned int index; unsigned int out_num; unsigned int in_num; - hwaddr in_addr[VIRTQUEUE_MAX_SIZE]; - hwaddr out_addr[VIRTQUEUE_MAX_SIZE]; - struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; - struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; + hwaddr *in_addr; + hwaddr *out_addr; + struct iovec *in_sg; + struct iovec *out_sg; } VirtQueueElement; #define VIRTIO_QUEUE_MAX 1024 @@ -143,6 +143,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void virtio_del_queue(VirtIODevice *vdev, int n); +void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num); void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); void virtqueue_flush(VirtQueue *vq, unsigned int count); From 3b3b0628217e2726069990ff9942a5d6d9816bd7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:29:01 +0100 Subject: [PATCH 09/45] virtio: slim down allocation of VirtQueueElements Build the addresses and s/g lists on the stack, and then copy them to a VirtQueueElement that is just as big as required to contain this particular s/g list. The cost of the copy is minimal compared to that of a large malloc. When virtqueue_map is used on the destination side of migration or on loadvm, the iovecs have already been split at memory region boundary, so we can just reuse the out_num/in_num we find in the file. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 82 ++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 661a1e1536..c3e00a8124 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -448,6 +448,32 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, return in_bytes <= in_total && out_bytes <= out_total; } +static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iovec *iov, + unsigned int max_num_sg, bool is_write, + hwaddr pa, size_t sz) +{ + unsigned num_sg = *p_num_sg; + assert(num_sg <= max_num_sg); + + while (sz) { + hwaddr len = sz; + + if (num_sg == max_num_sg) { + error_report("virtio: too many write descriptors in indirect table"); + exit(1); + } + + iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write); + iov[num_sg].iov_len = len; + addr[num_sg] = pa; + + sz -= len; + pa += len; + num_sg++; + } + *p_num_sg = num_sg; +} + static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, unsigned int *num_sg, unsigned int max_size, int is_write) @@ -474,20 +500,10 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, error_report("virtio: error trying to map MMIO memory"); exit(1); } - if (len == sg[i].iov_len) { - continue; - } - if (*num_sg >= max_size) { - error_report("virtio: memory split makes iovec too large"); + if (len != sg[i].iov_len) { + error_report("virtio: unexpected memory split"); exit(1); } - memmove(sg + i + 1, sg + i, sizeof(*sg) * (*num_sg - i)); - memmove(addr + i + 1, addr + i, sizeof(*addr) * (*num_sg - i)); - assert(len < sg[i + 1].iov_len); - sg[i].iov_len = len; - addr[i + 1] += len; - sg[i + 1].iov_len -= len; - ++*num_sg; } } @@ -526,14 +542,16 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) hwaddr desc_pa = vq->vring.desc; VirtIODevice *vdev = vq->vdev; VirtQueueElement *elem; + unsigned out_num, in_num; + hwaddr addr[VIRTQUEUE_MAX_SIZE]; + struct iovec iov[VIRTQUEUE_MAX_SIZE]; if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { return NULL; } /* When we start there are none of either input nor output. */ - elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); - elem->out_num = elem->in_num = 0; + out_num = in_num = 0; max = vq->vring.num; @@ -556,37 +574,39 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) /* Collect all the descriptors */ do { - struct iovec *sg; + hwaddr pa = vring_desc_addr(vdev, desc_pa, i); + size_t len = vring_desc_len(vdev, desc_pa, i); if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { - if (elem->in_num >= VIRTQUEUE_MAX_SIZE) { - error_report("Too many write descriptors in indirect table"); - exit(1); - } - elem->in_addr[elem->in_num] = vring_desc_addr(vdev, desc_pa, i); - sg = &elem->in_sg[elem->in_num++]; + virtqueue_map_desc(&in_num, addr + out_num, iov + out_num, + VIRTQUEUE_MAX_SIZE - out_num, true, pa, len); } else { - if (elem->out_num >= VIRTQUEUE_MAX_SIZE) { - error_report("Too many read descriptors in indirect table"); + if (in_num) { + error_report("Incorrect order for descriptors"); exit(1); } - elem->out_addr[elem->out_num] = vring_desc_addr(vdev, desc_pa, i); - sg = &elem->out_sg[elem->out_num++]; + virtqueue_map_desc(&out_num, addr, iov, + VIRTQUEUE_MAX_SIZE, false, pa, len); } - sg->iov_len = vring_desc_len(vdev, desc_pa, i); - /* If we've got too many, that implies a descriptor loop. */ - if ((elem->in_num + elem->out_num) > max) { + if ((in_num + out_num) > max) { error_report("Looped descriptor"); exit(1); } } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max); - /* Now map what we have collected */ - virtqueue_map(elem); - + /* Now copy what we have collected and mapped */ + elem = virtqueue_alloc_element(sz, out_num, in_num); elem->index = head; + for (i = 0; i < out_num; i++) { + elem->out_addr[i] = addr[i]; + elem->out_sg[i] = iov[i]; + } + for (i = 0; i < in_num; i++) { + elem->in_addr[i] = addr[out_num + i]; + elem->in_sg[i] = iov[out_num + i]; + } vq->inuse++; From 5dba97ebdc92f1ac3c9ac27d8eac52ed2348fae1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:29:02 +0100 Subject: [PATCH 10/45] vring: slim down allocation of VirtQueueElements Build the addresses and s/g lists on the stack, and then copy them to a VirtQueueElement that is just as big as required to contain this particular s/g list. The cost of the copy is minimal compared to that of a large malloc. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/dataplane/vring.c | 51 +++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 57ada3bcbe..4308d9f055 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -218,8 +218,14 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring) new, old); } +typedef struct VirtQueueCurrentElement { + unsigned in_num; + unsigned out_num; + hwaddr addr[VIRTQUEUE_MAX_SIZE]; + struct iovec iov[VIRTQUEUE_MAX_SIZE]; +} VirtQueueCurrentElement; -static int get_desc(Vring *vring, VirtQueueElement *elem, +static int get_desc(Vring *vring, VirtQueueCurrentElement *elem, struct vring_desc *desc) { unsigned *num; @@ -230,12 +236,12 @@ static int get_desc(Vring *vring, VirtQueueElement *elem, if (desc->flags & VRING_DESC_F_WRITE) { num = &elem->in_num; - iov = &elem->in_sg[*num]; - addr = &elem->in_addr[*num]; + iov = &elem->iov[elem->out_num + *num]; + addr = &elem->addr[elem->out_num + *num]; } else { num = &elem->out_num; - iov = &elem->out_sg[*num]; - addr = &elem->out_addr[*num]; + iov = &elem->iov[*num]; + addr = &elem->addr[*num]; /* If it's an output descriptor, they're all supposed * to come before any input descriptors. */ @@ -299,7 +305,8 @@ static bool read_vring_desc(VirtIODevice *vdev, /* This is stolen from linux/drivers/vhost/vhost.c. */ static int get_indirect(VirtIODevice *vdev, Vring *vring, - VirtQueueElement *elem, struct vring_desc *indirect) + VirtQueueCurrentElement *cur_elem, + struct vring_desc *indirect) { struct vring_desc desc; unsigned int i = 0, count, found = 0; @@ -351,7 +358,7 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring, return -EFAULT; } - ret = get_desc(vring, elem, &desc); + ret = get_desc(vring, cur_elem, &desc); if (ret < 0) { vring->broken |= (ret == -EFAULT); return ret; @@ -394,6 +401,7 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) struct vring_desc desc; unsigned int i, head, found = 0, num = vring->vr.num; uint16_t avail_idx, last_avail_idx; + VirtQueueCurrentElement cur_elem; VirtQueueElement *elem = NULL; int ret; @@ -403,10 +411,7 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) goto out; } - elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); - - /* Initialize elem so it can be safely unmapped */ - elem->in_num = elem->out_num = 0; + cur_elem.in_num = cur_elem.out_num = 0; /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vring->last_avail_idx; @@ -433,8 +438,6 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) * the index we've seen. */ head = vring_get_avail_ring(vdev, vring, last_avail_idx % num); - elem->index = head; - /* If their number is silly, that's an error. */ if (unlikely(head >= num)) { error_report("Guest says index %u > %u is available", head, num); @@ -461,14 +464,14 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) barrier(); if (desc.flags & VRING_DESC_F_INDIRECT) { - ret = get_indirect(vdev, vring, elem, &desc); + ret = get_indirect(vdev, vring, &cur_elem, &desc); if (ret < 0) { goto out; } continue; } - ret = get_desc(vring, elem, &desc); + ret = get_desc(vring, &cur_elem, &desc); if (ret < 0) { goto out; } @@ -483,6 +486,18 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) virtio_tswap16(vdev, vring->last_avail_idx); } + /* Now copy what we have collected and mapped */ + elem = virtqueue_alloc_element(sz, cur_elem.out_num, cur_elem.in_num); + elem->index = head; + for (i = 0; i < cur_elem.out_num; i++) { + elem->out_addr[i] = cur_elem.addr[i]; + elem->out_sg[i] = cur_elem.iov[i]; + } + for (i = 0; i < cur_elem.in_num; i++) { + elem->in_addr[i] = cur_elem.addr[cur_elem.out_num + i]; + elem->in_sg[i] = cur_elem.iov[cur_elem.out_num + i]; + } + return elem; out: @@ -490,7 +505,11 @@ out: if (ret == -EFAULT) { vring->broken = true; } - vring_unmap_element(elem); + + for (i = 0; i < cur_elem.out_num + cur_elem.in_num; i++) { + vring_unmap(cur_elem.iov[i].iov_base, false); + } + g_free(elem); return NULL; } From aa570d6fb6bd0402f27f151a76fb1762e26231ac Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:29:03 +0100 Subject: [PATCH 11/45] virtio: combine the read of a descriptor Compared to vring, virtio has a performance penalty of 10%. Fix it by combining all the reads for a descriptor in a single address_space_read call. This also simplifies the code nicely. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 86 +++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index c3e00a8124..225ee6d23f 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -107,35 +107,15 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n) vring->align); } -static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa, - int i) +static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, + hwaddr desc_pa, int i) { - hwaddr pa; - pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); - return virtio_ldq_phys(vdev, pa); -} - -static inline uint32_t vring_desc_len(VirtIODevice *vdev, hwaddr desc_pa, int i) -{ - hwaddr pa; - pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); - return virtio_ldl_phys(vdev, pa); -} - -static inline uint16_t vring_desc_flags(VirtIODevice *vdev, hwaddr desc_pa, - int i) -{ - hwaddr pa; - pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); - return virtio_lduw_phys(vdev, pa); -} - -static inline uint16_t vring_desc_next(VirtIODevice *vdev, hwaddr desc_pa, - int i) -{ - hwaddr pa; - pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); - return virtio_lduw_phys(vdev, pa); + address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc), + MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc)); + virtio_tswap64s(vdev, &desc->addr); + virtio_tswap32s(vdev, &desc->len); + virtio_tswap16s(vdev, &desc->flags); + virtio_tswap16s(vdev, &desc->next); } static inline uint16_t vring_avail_flags(VirtQueue *vq) @@ -345,18 +325,18 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) return head; } -static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa, - unsigned int i, unsigned int max) +static unsigned virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, + hwaddr desc_pa, unsigned int max) { unsigned int next; /* If this descriptor says it doesn't chain, we're done. */ - if (!(vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_NEXT)) { + if (!(desc->flags & VRING_DESC_F_NEXT)) { return max; } /* Check they're not leading us off end of descriptors. */ - next = vring_desc_next(vdev, desc_pa, i); + next = desc->next; /* Make sure compiler knows to grab that: we don't want it changing! */ smp_wmb(); @@ -365,6 +345,7 @@ static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa, exit(1); } + vring_desc_read(vdev, desc, desc_pa, next); return next; } @@ -381,6 +362,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, while (virtqueue_num_heads(vq, idx)) { VirtIODevice *vdev = vq->vdev; unsigned int max, num_bufs, indirect = 0; + VRingDesc desc; hwaddr desc_pa; int i; @@ -388,9 +370,10 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, num_bufs = total_bufs; i = virtqueue_get_head(vq, idx++); desc_pa = vq->vring.desc; + vring_desc_read(vdev, &desc, desc_pa, i); - if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) { - if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) { + if (desc.flags & VRING_DESC_F_INDIRECT) { + if (desc.len % sizeof(VRingDesc)) { error_report("Invalid size for indirect buffer table"); exit(1); } @@ -403,9 +386,10 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, /* loop over the indirect descriptor table */ indirect = 1; - max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc); - desc_pa = vring_desc_addr(vdev, desc_pa, i); + max = desc.len / sizeof(VRingDesc); + desc_pa = desc.addr; num_bufs = i = 0; + vring_desc_read(vdev, &desc, desc_pa, i); } do { @@ -415,15 +399,15 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, exit(1); } - if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { - in_total += vring_desc_len(vdev, desc_pa, i); + if (desc.flags & VRING_DESC_F_WRITE) { + in_total += desc.len; } else { - out_total += vring_desc_len(vdev, desc_pa, i); + out_total += desc.len; } if (in_total >= max_in_bytes && out_total >= max_out_bytes) { goto done; } - } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max); + } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max); if (!indirect) total_bufs = num_bufs; @@ -545,6 +529,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) unsigned out_num, in_num; hwaddr addr[VIRTQUEUE_MAX_SIZE]; struct iovec iov[VIRTQUEUE_MAX_SIZE]; + VRingDesc desc; if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { return NULL; @@ -560,33 +545,32 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) vring_set_avail_event(vq, vq->last_avail_idx); } - if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) { - if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) { + vring_desc_read(vdev, &desc, desc_pa, i); + if (desc.flags & VRING_DESC_F_INDIRECT) { + if (desc.len % sizeof(VRingDesc)) { error_report("Invalid size for indirect buffer table"); exit(1); } /* loop over the indirect descriptor table */ - max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc); - desc_pa = vring_desc_addr(vdev, desc_pa, i); + max = desc.len / sizeof(VRingDesc); + desc_pa = desc.addr; i = 0; + vring_desc_read(vdev, &desc, desc_pa, i); } /* Collect all the descriptors */ do { - hwaddr pa = vring_desc_addr(vdev, desc_pa, i); - size_t len = vring_desc_len(vdev, desc_pa, i); - - if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { + if (desc.flags & VRING_DESC_F_WRITE) { virtqueue_map_desc(&in_num, addr + out_num, iov + out_num, - VIRTQUEUE_MAX_SIZE - out_num, true, pa, len); + VIRTQUEUE_MAX_SIZE - out_num, true, desc.addr, desc.len); } else { if (in_num) { error_report("Incorrect order for descriptors"); exit(1); } virtqueue_map_desc(&out_num, addr, iov, - VIRTQUEUE_MAX_SIZE, false, pa, len); + VIRTQUEUE_MAX_SIZE, false, desc.addr, desc.len); } /* If we've got too many, that implies a descriptor loop. */ @@ -594,7 +578,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) error_report("Looped descriptor"); exit(1); } - } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max); + } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max); /* Now copy what we have collected and mapped */ elem = virtqueue_alloc_element(sz, out_num, in_num); From b796fcd1bf2978aed15748db04e054f34789e9eb Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 31 Jan 2016 11:29:04 +0100 Subject: [PATCH 12/45] virtio: cache used_idx in a VirtQueue field Accessing used_idx in the VQ requires an expensive access to guest physical memory. Before this patch, 3 accesses are normally done for each pop/push/notify call. However, since the used_idx is only written by us, we can track it in our internal data structure. Signed-off-by: Vincenzo Maffione Message-Id: <3d062ec54e9a7bf9fb325c1fd693564951f2b319.1450218353.git.v.maffione@gmail.com> Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 225ee6d23f..82e64144cc 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -71,6 +71,9 @@ struct VirtQueue { VRing vring; uint16_t last_avail_idx; + + uint16_t used_idx; + /* Last used index value we have signalled on */ uint16_t signalled_used; @@ -170,6 +173,7 @@ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, idx); virtio_stw_phys(vq->vdev, pa, val); + vq->used_idx = val; } static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) @@ -261,7 +265,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, virtqueue_unmap_sg(vq, elem, len); - idx = (idx + vring_used_idx(vq)) % vq->vring.num; + idx = (idx + vq->used_idx) % vq->vring.num; /* Get a pointer to the next entry in the used ring. */ vring_used_ring_id(vq, idx, elem->index); @@ -274,7 +278,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count) /* Make sure buffer is written before we update index. */ smp_wmb(); trace_virtqueue_flush(vq, count); - old = vring_used_idx(vq); + old = vq->used_idx; new = old + count; vring_used_idx_set(vq, new); vq->inuse -= count; @@ -782,6 +786,7 @@ void virtio_reset(void *opaque) vdev->vq[i].vring.avail = 0; vdev->vq[i].vring.used = 0; vdev->vq[i].last_avail_idx = 0; + vdev->vq[i].used_idx = 0; virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); vdev->vq[i].signalled_used = 0; vdev->vq[i].signalled_used_valid = false; @@ -1161,7 +1166,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq) v = vq->signalled_used_valid; vq->signalled_used_valid = true; old = vq->signalled_used; - new = vq->signalled_used = vring_used_idx(vq); + new = vq->signalled_used = vq->used_idx; return !v || vring_need_event(vring_get_used_event(vq), new, old); } @@ -1573,6 +1578,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) vdev->vq[i].last_avail_idx, nheads); return -1; } + vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]); } } From be1fea9bc286f64c6c995bb0d7145a0b738aeddb Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 31 Jan 2016 11:29:05 +0100 Subject: [PATCH 13/45] virtio: read avail_idx from VQ only when necessary The virtqueue_pop() implementation needs to check if the avail ring contains some pending buffers. To perform this check, it is not always necessary to fetch the avail_idx in the VQ memory, which is expensive. This patch introduces a shadow variable tracking avail_idx and modifies virtio_queue_empty() to access avail_idx in physical memory only when necessary. Signed-off-by: Vincenzo Maffione Message-Id: Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 82e64144cc..9608358c85 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -70,8 +70,13 @@ typedef struct VRing struct VirtQueue { VRing vring; + + /* Next head to pop */ uint16_t last_avail_idx; + /* Last avail_idx read from VQ. */ + uint16_t shadow_avail_idx; + uint16_t used_idx; /* Last used index value we have signalled on */ @@ -132,7 +137,8 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq) { hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, idx); - return virtio_lduw_phys(vq->vdev, pa); + vq->shadow_avail_idx = virtio_lduw_phys(vq->vdev, pa); + return vq->shadow_avail_idx; } static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) @@ -223,8 +229,14 @@ int virtio_queue_ready(VirtQueue *vq) return vq->vring.avail != 0; } +/* Fetch avail_idx from VQ memory only when we really need to know if + * guest has added some buffers. */ int virtio_queue_empty(VirtQueue *vq) { + if (vq->shadow_avail_idx != vq->last_avail_idx) { + return 0; + } + return vring_avail_idx(vq) == vq->last_avail_idx; } @@ -300,7 +312,7 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vq->vring.num) { error_report("Guest moved used index from %u to %u", - idx, vring_avail_idx(vq)); + idx, vq->shadow_avail_idx); exit(1); } /* On success, callers read a descriptor at vq->last_avail_idx. @@ -535,9 +547,12 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) struct iovec iov[VIRTQUEUE_MAX_SIZE]; VRingDesc desc; - if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { + if (virtio_queue_empty(vq)) { return NULL; } + /* Needed after virtio_queue_empty(), see comment in + * virtqueue_num_heads(). */ + smp_rmb(); /* When we start there are none of either input nor output. */ out_num = in_num = 0; @@ -786,6 +801,7 @@ void virtio_reset(void *opaque) vdev->vq[i].vring.avail = 0; vdev->vq[i].vring.used = 0; vdev->vq[i].last_avail_idx = 0; + vdev->vq[i].shadow_avail_idx = 0; vdev->vq[i].used_idx = 0; virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); vdev->vq[i].signalled_used = 0; @@ -1155,7 +1171,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq) smp_mb(); /* Always notify when queue is empty (when feature acknowledge) */ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && - !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx) { + !vq->inuse && virtio_queue_empty(vq)) { return true; } @@ -1579,6 +1595,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) return -1; } vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]); + vdev->vq[i].shadow_avail_idx = vring_avail_idx(&vdev->vq[i]); } } @@ -1714,6 +1731,7 @@ uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n) void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx) { vdev->vq[n].last_avail_idx = idx; + vdev->vq[n].shadow_avail_idx = idx; } void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n) From 1cdd2ee54a61ed288e56bd57a649ec50a5a88e8b Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 31 Jan 2016 11:29:06 +0100 Subject: [PATCH 14/45] virtio: combine write of an entry into used ring Fill in an element of the used ring with a single combined access to the guest physical memory, rather than using two separated accesses. This reduces the overhead due to expensive address translation. Signed-off-by: Vincenzo Maffione Message-Id: Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9608358c85..90f25451d0 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -153,18 +153,15 @@ static inline uint16_t vring_get_used_event(VirtQueue *vq) return vring_avail_ring(vq, vq->vring.num); } -static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val) +static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, + int i) { hwaddr pa; - pa = vq->vring.used + offsetof(VRingUsed, ring[i].id); - virtio_stl_phys(vq->vdev, pa, val); -} - -static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val) -{ - hwaddr pa; - pa = vq->vring.used + offsetof(VRingUsed, ring[i].len); - virtio_stl_phys(vq->vdev, pa, val); + virtio_tswap32s(vq->vdev, &uelem->id); + virtio_tswap32s(vq->vdev, &uelem->len); + pa = vq->vring.used + offsetof(VRingUsed, ring[i]); + address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED, + (void *)uelem, sizeof(VRingUsedElem)); } static uint16_t vring_used_idx(VirtQueue *vq) @@ -273,15 +270,17 @@ void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx) { + VRingUsedElem uelem; + trace_virtqueue_fill(vq, elem, len, idx); virtqueue_unmap_sg(vq, elem, len); idx = (idx + vq->used_idx) % vq->vring.num; - /* Get a pointer to the next entry in the used ring. */ - vring_used_ring_id(vq, idx, elem->index); - vring_used_ring_len(vq, idx, len); + uelem.id = elem->index; + uelem.len = len; + vring_used_write(vq, &uelem, idx); } void virtqueue_flush(VirtQueue *vq, unsigned int count) From 13d11b0ba85c8a02b0527fa360286e1f68c59b22 Mon Sep 17 00:00:00 2001 From: Marcel Apfelbaum Date: Wed, 3 Feb 2016 13:56:10 +0200 Subject: [PATCH 15/45] hw/pxb: add pxb devices to the bridge category Signed-off-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-bridge/pci_expander_bridge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 62fd29d891..d23b8da488 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -302,6 +302,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Expander Bridge"; dc->props = pxb_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo pxb_dev_info = { @@ -334,6 +335,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Express Expander Bridge"; dc->props = pxb_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo pxb_pcie_dev_info = { From b5c6eaf173cbeec414b2d837c5703515f979f2af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Feb 2016 16:00:52 +0100 Subject: [PATCH 16/45] vhost-user-test: use correct ROM to speed up and avoid spurious failures The mechanism to get the option ROM for virtio-net does not block the PCI ROM from being loaded. Therefore, in vhost-user-test there are two entries in the boot menu for the virtio-net card: one as an embedded option ROM, one from the ROM BAR. The embedded option ROM in vhost-user-test is the non-EFI-enabled, while the ROM BAR has an EFI-enabled ROM. The two are compiled with slightly different parameters, where only the old BIOS-only one doesn't have a timeout for the "Press Ctrl-B" banner. When using a new machine type, therefore, the vhost-user-test has to wait for the EFI-enabled ROM's banner to go away. There are several ways to fix this: 1) fix the ROMs to have the same configuration 2) add ",romfile=" to the -device line 3) remove --option-rom and add the ROM file name to the -device line 4) use an old machine type This patch chooses 3. In addition, the file name was wrong because qtest runs QEMU relative to the top build directory, not to the x86_64-softmmu/ subdirectory, which is fixed too. Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/vhost-user-test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 95f35af3e5..e30b7f4abc 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -35,11 +35,10 @@ "mem-path=%s,share=on -numa node,memdev=mem" #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s" #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce" -#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0 " -#define QEMU_CMD_ROM " -option-rom ../pc-bios/pxe-virtio.rom" +#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0,romfile=./pc-bios/pxe-virtio.rom" #define QEMU_CMD QEMU_CMD_ACCEL QEMU_CMD_MEM QEMU_CMD_CHR \ - QEMU_CMD_NETDEV QEMU_CMD_NET QEMU_CMD_ROM + QEMU_CMD_NETDEV QEMU_CMD_NET #define HUGETLBFS_MAGIC 0x958458f6 From 0144f6f1ce536b2c56a9b16ef189fc81c3bcb82f Mon Sep 17 00:00:00 2001 From: Marcel Apfelbaum Date: Mon, 18 Jan 2016 17:27:26 +0200 Subject: [PATCH 17/45] hw/pci: ensure that only PCI/PCIe bridges can be attached to pxb/pxb-pcie devices PCI devices can't be plugged directly into PCI extra root bridges because their resources can't be computed by firmware before the ACPI tables are loaded. Signed-off-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index d940f79de0..b282120b12 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -851,6 +851,13 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, DeviceState *dev = DEVICE(pci_dev); pci_dev->bus = bus; + /* Only pci bridges can be attached to extra PCI root buses */ + if (pci_bus_is_root(bus) && bus->parent_dev && !pc->is_bridge) { + error_setg(errp, + "PCI: Only PCI/PCIe bridges can be plugged into %s", + bus->parent_dev->name); + return NULL; + } if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); From d13ada5d8f5064615db3a6bf5ef457cb159e3dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:27 +0100 Subject: [PATCH 18/45] ipmi: replace goto by a return statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each routine using the IPMI_ADD_RSP_DATA, IPMI_CHECK_CMD_LEN or IPMI_CHECK_RESERVATION macros needs to define a goto label 'out' to handle hidden errors. Using directly a return statement has the same effect and it removes the fact that 'out' needs to be defined. The code exits in ipmi_sim_handle_command() are a little different from the rest and a "possible" error in the macro IPMI_ADD_RSP_DATA is handled before making use of it. This might be a bit excessive as a minimum response len is currently 300 bytes and the patch checks that at least 3 are available. Signed-off-by: Cédric Le Goater Reviewed-by: Marcel Apfelbaum Reviewed-by: Greg Kurz Reviewed-by: Corey Minyard Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 140 ++++++++++++----------------------------- 1 file changed, 41 insertions(+), 99 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index dcdab035d6..1f06dfcb8a 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -256,7 +256,7 @@ struct IPMIBmcSim { do { \ if (*rsp_len >= max_rsp_len) { \ rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \ - goto out; \ + return; \ } \ rsp[(*rsp_len)++] = (b); \ } while (0) @@ -265,7 +265,7 @@ struct IPMIBmcSim { #define IPMI_CHECK_CMD_LEN(l) \ if (cmd_len < l) { \ rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \ - goto out; \ + return; \ } /* Check that the reservation in the command is valid. */ @@ -273,7 +273,7 @@ struct IPMIBmcSim { do { \ if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \ rsp[2] = IPMI_CC_INVALID_RESERVATION; \ - goto out; \ + return; \ } \ } while (0) @@ -451,14 +451,12 @@ static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, } if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { - goto out; + return; } memcpy(ibs->evtbuf, evt, 16); ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; k->set_atn(s, 1, attn_irq_enabled(ibs)); - out: - return; } static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, @@ -579,6 +577,11 @@ static void ipmi_sim_handle_command(IPMIBmc *b, /* Set up the response, set the low bit of NETFN. */ /* Note that max_rsp_len must be at least 3 */ + if (max_rsp_len < 3) { + rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; + goto out; + } + IPMI_ADD_RSP_DATA(cmd[0] | 0x04); IPMI_ADD_RSP_DATA(cmd[1]); IPMI_ADD_RSP_DATA(0); /* Assume success */ @@ -696,8 +699,6 @@ static void chassis_capabilities(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); - out: - return; } static void chassis_status(IPMIBmcSim *ibs, @@ -709,8 +710,6 @@ static void chassis_status(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(0); IPMI_ADD_RSP_DATA(0); IPMI_ADD_RSP_DATA(0); - out: - return; } static void chassis_control(IPMIBmcSim *ibs, @@ -744,10 +743,8 @@ static void chassis_control(IPMIBmcSim *ibs, break; default: rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } - out: - return; } static void get_device_id(IPMIBmcSim *ibs, @@ -766,8 +763,6 @@ static void get_device_id(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(ibs->mfg_id[2]); IPMI_ADD_RSP_DATA(ibs->product_id[0]); IPMI_ADD_RSP_DATA(ibs->product_id[1]); - out: - return; } static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) @@ -820,8 +815,6 @@ static void set_bmc_global_enables(IPMIBmcSim *ibs, { IPMI_CHECK_CMD_LEN(3); set_global_enables(ibs, cmd[2]); - out: - return; } static void get_bmc_global_enables(IPMIBmcSim *ibs, @@ -830,8 +823,6 @@ static void get_bmc_global_enables(IPMIBmcSim *ibs, unsigned int max_rsp_len) { IPMI_ADD_RSP_DATA(ibs->bmc_global_enables); - out: - return; } static void clr_msg_flags(IPMIBmcSim *ibs, @@ -845,8 +836,6 @@ static void clr_msg_flags(IPMIBmcSim *ibs, IPMI_CHECK_CMD_LEN(3); ibs->msg_flags &= ~cmd[2]; k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); - out: - return; } static void get_msg_flags(IPMIBmcSim *ibs, @@ -855,8 +844,6 @@ static void get_msg_flags(IPMIBmcSim *ibs, unsigned int max_rsp_len) { IPMI_ADD_RSP_DATA(ibs->msg_flags); - out: - return; } static void read_evt_msg_buf(IPMIBmcSim *ibs, @@ -870,15 +857,13 @@ static void read_evt_msg_buf(IPMIBmcSim *ibs, if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { rsp[2] = 0x80; - goto out; + return; } for (i = 0; i < 16; i++) { IPMI_ADD_RSP_DATA(ibs->evtbuf[i]); } ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); - out: - return; } static void get_msg(IPMIBmcSim *ibs, @@ -909,7 +894,7 @@ static void get_msg(IPMIBmcSim *ibs, k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); } - out: +out: qemu_mutex_unlock(&ibs->lock); return; } @@ -940,14 +925,14 @@ static void send_msg(IPMIBmcSim *ibs, if (cmd[2] != 0) { /* We only handle channel 0 with no options */ rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } IPMI_CHECK_CMD_LEN(10); if (cmd[3] != 0x40) { /* We only emulate a MC at address 0x40. */ rsp[2] = 0x83; /* NAK on write */ - goto out; + return; } cmd += 3; /* Skip the header. */ @@ -959,7 +944,7 @@ static void send_msg(IPMIBmcSim *ibs, */ if (ipmb_checksum(cmd, cmd_len, 0) != 0 || cmd[3] != 0x20) { /* Improper response address */ - goto out; /* No response */ + return; /* No response */ } netfn = cmd[1] >> 2; @@ -969,7 +954,7 @@ static void send_msg(IPMIBmcSim *ibs, if (rqLun != 2) { /* We only support LUN 2 coming back to us. */ - goto out; + return; } msg = g_malloc(sizeof(*msg)); @@ -1009,9 +994,6 @@ static void send_msg(IPMIBmcSim *ibs, ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; k->set_atn(s, 1, attn_irq_enabled(ibs)); qemu_mutex_unlock(&ibs->lock); - - out: - return; } static void do_watchdog_reset(IPMIBmcSim *ibs) @@ -1040,11 +1022,9 @@ static void reset_watchdog_timer(IPMIBmcSim *ibs, { if (!ibs->watchdog_initialized) { rsp[2] = 0x80; - goto out; + return; } do_watchdog_reset(ibs); - out: - return; } static void set_watchdog_timer(IPMIBmcSim *ibs, @@ -1060,7 +1040,7 @@ static void set_watchdog_timer(IPMIBmcSim *ibs, val = cmd[2] & 0x7; /* Validate use */ if (val == 0 || val > 5) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } val = cmd[3] & 0x7; /* Validate action */ switch (val) { @@ -1084,7 +1064,7 @@ static void set_watchdog_timer(IPMIBmcSim *ibs, } if (rsp[2]) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ @@ -1097,12 +1077,12 @@ static void set_watchdog_timer(IPMIBmcSim *ibs, if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { /* NMI not supported. */ rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } default: /* We don't support PRE_SMI */ rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } ibs->watchdog_initialized = 1; @@ -1116,8 +1096,6 @@ static void set_watchdog_timer(IPMIBmcSim *ibs, } else { ibs->watchdog_running = 0; } - out: - return; } static void get_watchdog_timer(IPMIBmcSim *ibs, @@ -1139,8 +1117,6 @@ static void get_watchdog_timer(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(0); IPMI_ADD_RSP_DATA(0); } - out: - return; } static void get_sdr_rep_info(IPMIBmcSim *ibs, @@ -1163,8 +1139,6 @@ static void get_sdr_rep_info(IPMIBmcSim *ibs, } /* Only modal support, reserve supported */ IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22); - out: - return; } static void reserve_sdr_rep(IPMIBmcSim *ibs, @@ -1174,8 +1148,6 @@ static void reserve_sdr_rep(IPMIBmcSim *ibs, { IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff); IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff); - out: - return; } static void get_sdr(IPMIBmcSim *ibs, @@ -1194,11 +1166,11 @@ static void get_sdr(IPMIBmcSim *ibs, if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), &pos, &nextrec)) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } if (cmd[6] > (ibs->sdr.sdr[pos + 4])) { rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; - goto out; + return; } IPMI_ADD_RSP_DATA(nextrec & 0xff); @@ -1210,12 +1182,10 @@ static void get_sdr(IPMIBmcSim *ibs, if ((cmd[7] + *rsp_len) > max_rsp_len) { rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; - goto out; + return; } memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]); *rsp_len += cmd[7]; - out: - return; } static void add_sdr(IPMIBmcSim *ibs, @@ -1227,12 +1197,10 @@ static void add_sdr(IPMIBmcSim *ibs, if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } IPMI_ADD_RSP_DATA(recid & 0xff); IPMI_ADD_RSP_DATA((recid >> 8) & 0xff); - out: - return; } static void clear_sdr_rep(IPMIBmcSim *ibs, @@ -1244,7 +1212,7 @@ static void clear_sdr_rep(IPMIBmcSim *ibs, IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } if (cmd[7] == 0xaa) { ibs->sdr.next_free = 0; @@ -1256,10 +1224,8 @@ static void clear_sdr_rep(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(1); /* Erasure complete */ } else { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } - out: - return; } static void get_sel_info(IPMIBmcSim *ibs, @@ -1283,8 +1249,6 @@ static void get_sel_info(IPMIBmcSim *ibs, } /* Only support Reserve SEL */ IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); - out: - return; } static void reserve_sel(IPMIBmcSim *ibs, @@ -1294,8 +1258,6 @@ static void reserve_sel(IPMIBmcSim *ibs, { IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff); IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff); - out: - return; } static void get_sel_entry(IPMIBmcSim *ibs, @@ -1311,17 +1273,17 @@ static void get_sel_entry(IPMIBmcSim *ibs, } if (ibs->sel.next_free == 0) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } if (cmd[6] > 15) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } if (cmd[7] == 0xff) { cmd[7] = 16; } else if ((cmd[7] + cmd[6]) > 16) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } else { cmd[7] += cmd[6]; } @@ -1331,7 +1293,7 @@ static void get_sel_entry(IPMIBmcSim *ibs, val = ibs->sel.next_free - 1; } else if (val >= ibs->sel.next_free) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } if ((val + 1) == ibs->sel.next_free) { IPMI_ADD_RSP_DATA(0xff); @@ -1343,8 +1305,6 @@ static void get_sel_entry(IPMIBmcSim *ibs, for (; cmd[6] < cmd[7]; cmd[6]++) { IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]); } - out: - return; } static void add_sel_entry(IPMIBmcSim *ibs, @@ -1355,13 +1315,11 @@ static void add_sel_entry(IPMIBmcSim *ibs, IPMI_CHECK_CMD_LEN(18); if (sel_add_event(ibs, cmd + 2)) { rsp[2] = IPMI_CC_OUT_OF_SPACE; - goto out; + return; } /* sel_add_event fills in the record number. */ IPMI_ADD_RSP_DATA(cmd[2]); IPMI_ADD_RSP_DATA(cmd[3]); - out: - return; } static void clear_sel(IPMIBmcSim *ibs, @@ -1373,7 +1331,7 @@ static void clear_sel(IPMIBmcSim *ibs, IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } if (cmd[7] == 0xaa) { ibs->sel.next_free = 0; @@ -1385,10 +1343,8 @@ static void clear_sel(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA(1); /* Erasure complete */ } else { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } - out: - return; } static void get_sel_time(IPMIBmcSim *ibs, @@ -1405,8 +1361,6 @@ static void get_sel_time(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((val >> 8) & 0xff); IPMI_ADD_RSP_DATA((val >> 16) & 0xff); IPMI_ADD_RSP_DATA((val >> 24) & 0xff); - out: - return; } static void set_sel_time(IPMIBmcSim *ibs, @@ -1421,8 +1375,6 @@ static void set_sel_time(IPMIBmcSim *ibs, val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); ipmi_gettime(&now); ibs->sel.time_offset = now.tv_sec - ((long) val); - out: - return; } static void set_sensor_evt_enable(IPMIBmcSim *ibs, @@ -1436,7 +1388,7 @@ static void set_sensor_evt_enable(IPMIBmcSim *ibs, if ((cmd[2] > MAX_SENSORS) || !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } sens = ibs->sensors + cmd[2]; switch ((cmd[3] >> 4) & 0x3) { @@ -1472,11 +1424,9 @@ static void set_sensor_evt_enable(IPMIBmcSim *ibs, break; case 3: rsp[2] = IPMI_CC_INVALID_DATA_FIELD; - goto out; + return; } IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); - out: - return; } static void get_sensor_evt_enable(IPMIBmcSim *ibs, @@ -1490,7 +1440,7 @@ static void get_sensor_evt_enable(IPMIBmcSim *ibs, if ((cmd[2] > MAX_SENSORS) || !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } sens = ibs->sensors + cmd[2]; IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); @@ -1498,8 +1448,6 @@ static void get_sensor_evt_enable(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff); IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff); IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff); - out: - return; } static void rearm_sensor_evts(IPMIBmcSim *ibs, @@ -1513,17 +1461,15 @@ static void rearm_sensor_evts(IPMIBmcSim *ibs, if ((cmd[2] > MAX_SENSORS) || !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } sens = ibs->sensors + cmd[2]; if ((cmd[3] & 0x80) == 0) { /* Just clear everything */ sens->states = 0; - goto out; + return; } - out: - return; } static void get_sensor_evt_status(IPMIBmcSim *ibs, @@ -1537,7 +1483,7 @@ static void get_sensor_evt_status(IPMIBmcSim *ibs, if ((cmd[2] > MAX_SENSORS) || !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } sens = ibs->sensors + cmd[2]; IPMI_ADD_RSP_DATA(sens->reading); @@ -1546,8 +1492,6 @@ static void get_sensor_evt_status(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff); IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff); IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff); - out: - return; } static void get_sensor_reading(IPMIBmcSim *ibs, @@ -1561,7 +1505,7 @@ static void get_sensor_reading(IPMIBmcSim *ibs, if ((cmd[2] > MAX_SENSORS) || !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; - goto out; + return; } sens = ibs->sensors + cmd[2]; IPMI_ADD_RSP_DATA(sens->reading); @@ -1570,8 +1514,6 @@ static void get_sensor_reading(IPMIBmcSim *ibs, if (IPMI_SENSOR_IS_DISCRETE(sens)) { IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff); } - out: - return; } static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = { From 62a4931d1e719059a8462dc0adad812524796fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:28 +0100 Subject: [PATCH 19/45] ipmi: replace *_MAXCMD defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARRAY_SIZE() is simple to use and removes the need to pre-define the size of the command arrays. Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 1f06dfcb8a..f7e87b479b 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -28,14 +28,12 @@ #include "qemu/error-report.h" #define IPMI_NETFN_CHASSIS 0x00 -#define IPMI_NETFN_CHASSIS_MAXCMD 0x03 #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 #define IPMI_CMD_CHASSIS_CONTROL 0x02 #define IPMI_NETFN_SENSOR_EVENT 0x04 -#define IPMI_NETFN_SENSOR_EVENT_MAXCMD 0x2e #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 @@ -44,7 +42,6 @@ #define IPMI_CMD_GET_SENSOR_READING 0x2d /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ -#define IPMI_NETFN_APP_MAXCMD 0x36 #define IPMI_CMD_GET_DEVICE_ID 0x01 #define IPMI_CMD_COLD_RESET 0x02 @@ -61,7 +58,6 @@ #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 #define IPMI_NETFN_STORAGE 0x0a -#define IPMI_NETFN_STORAGE_MAXCMD 0x4a #define IPMI_CMD_GET_SDR_REP_INFO 0x20 #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 @@ -1516,18 +1512,17 @@ static void get_sensor_reading(IPMIBmcSim *ibs, } } -static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = { +static const IPMICmdHandler chassis_cmds[] = { [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, [IPMI_CMD_CHASSIS_CONTROL] = chassis_control }; static const IPMINetfn chassis_netfn = { - .cmd_nums = IPMI_NETFN_CHASSIS_MAXCMD, + .cmd_nums = ARRAY_SIZE(chassis_cmds), .cmd_handlers = chassis_cmds }; -static const IPMICmdHandler -sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = { +static const IPMICmdHandler sensor_event_cmds[] = { [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable, [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, @@ -1535,11 +1530,11 @@ sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = { [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading }; static const IPMINetfn sensor_event_netfn = { - .cmd_nums = IPMI_NETFN_SENSOR_EVENT_MAXCMD, + .cmd_nums = ARRAY_SIZE(sensor_event_cmds), .cmd_handlers = sensor_event_cmds }; -static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = { +static const IPMICmdHandler app_cmds[] = { [IPMI_CMD_GET_DEVICE_ID] = get_device_id, [IPMI_CMD_COLD_RESET] = cold_reset, [IPMI_CMD_WARM_RESET] = warm_reset, @@ -1555,11 +1550,11 @@ static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = { [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer, }; static const IPMINetfn app_netfn = { - .cmd_nums = IPMI_NETFN_APP_MAXCMD, + .cmd_nums = ARRAY_SIZE(app_cmds), .cmd_handlers = app_cmds }; -static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = { +static const IPMICmdHandler storage_cmds[] = { [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, [IPMI_CMD_GET_SDR] = get_sdr, @@ -1575,7 +1570,7 @@ static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = { }; static const IPMINetfn storage_netfn = { - .cmd_nums = IPMI_NETFN_STORAGE_MAXCMD, + .cmd_nums = ARRAY_SIZE(storage_cmds), .cmd_handlers = storage_cmds }; From 7cfa06a2f1db6fef2be7f645697dbc6c4006324a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:29 +0100 Subject: [PATCH 20/45] ipmi: cleanup error_report messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Cc: Greg Kurz Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index f7e87b479b..d8ca76aea7 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -1644,7 +1644,7 @@ static void ipmi_sim_init(Object *obj) for (i = 0;;) { int len; if ((i + 5) > sizeof(init_sdrs)) { - error_report("Problem with recid 0x%4.4x: \n", i); + error_report("Problem with recid 0x%4.4x", i); return; } len = init_sdrs[i + 4]; @@ -1653,7 +1653,7 @@ static void ipmi_sim_init(Object *obj) break; } if ((i + len + 5) > sizeof(init_sdrs)) { - error_report("Problem with recid 0x%4.4x\n", i); + error_report("Problem with recid 0x%4.4x", i); return; } sdr_add_entry(ibs, init_sdrs + i, len, NULL); From 792afddb4a5cb2da11a57cfdb124b78981ed1fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:30 +0100 Subject: [PATCH 21/45] ipmi: fix SDR length value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The IPMI BMC simulator populates the SDR table with a set of initial SDRs. The length of each SDR is taken from the record itself (byte 4) which does not include the size of the header. But, the full length (header + data) is required by the sdr_add_entry() routine. Signed-off-by: Cédric Le Goater Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index d8ca76aea7..73a4f6a7ab 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -356,7 +356,7 @@ static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, while (pos < sdr->next_free) { uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8); - unsigned int nextpos = pos + sdr->sdr[pos + 4]; + unsigned int nextpos = pos + sdr->sdr[pos + 4] + 5; if (trec == recid) { if (nextrec) { @@ -1164,7 +1164,7 @@ static void get_sdr(IPMIBmcSim *ibs, rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; return; } - if (cmd[6] > (ibs->sdr.sdr[pos + 4])) { + if (cmd[6] > (ibs->sdr.sdr[pos + 4] + 5)) { rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; return; } @@ -1173,7 +1173,7 @@ static void get_sdr(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); if (cmd[7] == 0xff) { - cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6]; + cmd[7] = ibs->sdr.sdr[pos + 4] + 5 - cmd[6]; } if ((cmd[7] + *rsp_len) > max_rsp_len) { @@ -1647,17 +1647,17 @@ static void ipmi_sim_init(Object *obj) error_report("Problem with recid 0x%4.4x", i); return; } - len = init_sdrs[i + 4]; + len = init_sdrs[i + 4] + 5; recid = init_sdrs[i] | (init_sdrs[i + 1] << 8); if (recid == 0xffff) { break; } - if ((i + len + 5) > sizeof(init_sdrs)) { + if ((i + len) > sizeof(init_sdrs)) { error_report("Problem with recid 0x%4.4x", i); return; } sdr_add_entry(ibs, init_sdrs + i, len, NULL); - i += len + 5; + i += len; } ipmi_init_sensors_from_sdrs(ibs); From a2295f0a5871e2b9d8ea24bc3a1d2e02bda6ef2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:31 +0100 Subject: [PATCH 22/45] ipmi: introduce a struct ipmi_sdr_compact MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, sdr attributes are identified using byte offsets and this can be a bit confusing. This patch adds a struct ipmi_sdr_compact conforming to the IPMI specs and replaces byte offsets with names. It also introduces and uses a struct ipmi_sdr_header in sections of the code where no assumption is made on the type of SDR. This leave rooms to potential usage of other types in the future. Signed-off-by: Cédric Le Goater Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 72 ++++++++++++++++++++++++++---------------- include/hw/ipmi/ipmi.h | 45 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 28 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 73a4f6a7ab..84fbcd2638 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -318,14 +318,18 @@ static void sdr_inc_reservation(IPMISdr *sdr) } } -static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry, +static int sdr_add_entry(IPMIBmcSim *ibs, + const struct ipmi_sdr_header *sdrh_entry, unsigned int len, uint16_t *recid) { - if ((len < 5) || (len > 255)) { + struct ipmi_sdr_header *sdrh = + (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; + + if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { return 1; } - if (entry[4] != len - 5) { + if (ipmi_sdr_length(sdrh_entry) != len) { return 1; } @@ -334,10 +338,10 @@ static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry, return 1; } - memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len); - ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff; - ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff; - ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */ + memcpy(sdrh, sdrh_entry, len); + sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; + sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; + sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ if (recid) { *recid = ibs->sdr.next_rec_id; @@ -355,8 +359,10 @@ static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, unsigned int pos = *retpos; while (pos < sdr->next_free) { - uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8); - unsigned int nextpos = pos + sdr->sdr[pos + 4] + 5; + struct ipmi_sdr_header *sdrh = + (struct ipmi_sdr_header *) &sdr->sdr[pos]; + uint16_t trec = ipmi_sdr_recid(sdrh); + unsigned int nextpos = pos + ipmi_sdr_length(sdrh); if (trec == recid) { if (nextrec) { @@ -505,29 +511,32 @@ static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) pos = 0; for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { - uint8_t *sdr = s->sdr.sdr + pos; - unsigned int len = sdr[4]; + struct ipmi_sdr_compact *sdr = + (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; + unsigned int len = sdr->header.rec_length; if (len < 20) { continue; } - if ((sdr[3] < 1) || (sdr[3] > 2)) { + if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { continue; /* Not a sensor SDR we set from */ } - if (sdr[7] > MAX_SENSORS) { + if (sdr->sensor_owner_number > MAX_SENSORS) { continue; } - sens = s->sensors + sdr[7]; + sens = s->sensors + sdr->sensor_owner_number; IPMI_SENSOR_SET_PRESENT(sens, 1); - IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1); - IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1); - sens->assert_suppt = sdr[14] | (sdr[15] << 8); - sens->deassert_suppt = sdr[16] | (sdr[17] << 8); - sens->states_suppt = sdr[18] | (sdr[19] << 8); - sens->sensor_type = sdr[12]; - sens->evt_reading_type_code = sdr[13] & 0x7f; + IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); + IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); + sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); + sens->deassert_suppt = + sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); + sens->states_suppt = + sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); + sens->sensor_type = sdr->sensor_type; + sens->evt_reading_type_code = sdr->reading_type & 0x7f; /* Enable all the events that are supported. */ sens->assert_enable = sens->assert_suppt; @@ -1153,6 +1162,7 @@ static void get_sdr(IPMIBmcSim *ibs, { unsigned int pos; uint16_t nextrec; + struct ipmi_sdr_header *sdrh; IPMI_CHECK_CMD_LEN(8); if (cmd[6]) { @@ -1164,7 +1174,10 @@ static void get_sdr(IPMIBmcSim *ibs, rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; return; } - if (cmd[6] > (ibs->sdr.sdr[pos + 4] + 5)) { + + sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; + + if (cmd[6] > ipmi_sdr_length(sdrh)) { rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; return; } @@ -1173,7 +1186,7 @@ static void get_sdr(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); if (cmd[7] == 0xff) { - cmd[7] = ibs->sdr.sdr[pos + 4] + 5 - cmd[6]; + cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; } if ((cmd[7] + *rsp_len) > max_rsp_len) { @@ -1190,8 +1203,9 @@ static void add_sdr(IPMIBmcSim *ibs, unsigned int max_rsp_len) { uint16_t recid; + struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; - if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) { + if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { rsp[2] = IPMI_CC_INVALID_DATA_FIELD; return; } @@ -1642,13 +1656,15 @@ static void ipmi_sim_init(Object *obj) } for (i = 0;;) { + struct ipmi_sdr_header *sdrh; int len; - if ((i + 5) > sizeof(init_sdrs)) { + if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { error_report("Problem with recid 0x%4.4x", i); return; } - len = init_sdrs[i + 4] + 5; - recid = init_sdrs[i] | (init_sdrs[i + 1] << 8); + sdrh = (struct ipmi_sdr_header *) &init_sdrs[i]; + len = ipmi_sdr_length(sdrh); + recid = ipmi_sdr_recid(sdrh); if (recid == 0xffff) { break; } @@ -1656,7 +1672,7 @@ static void ipmi_sim_init(Object *obj) error_report("Problem with recid 0x%4.4x", i); return; } - sdr_add_entry(ibs, init_sdrs + i, len, NULL); + sdr_add_entry(ibs, sdrh, len, NULL); i += len; } diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h index 32bac0fa88..74a2b5af96 100644 --- a/include/hw/ipmi/ipmi.h +++ b/include/hw/ipmi/ipmi.h @@ -210,4 +210,49 @@ IPMIFwInfo *ipmi_next_fwinfo(IPMIFwInfo *current); #define ipmi_debug(fs, ...) #endif +struct ipmi_sdr_header { + uint8_t rec_id[2]; + uint8_t sdr_version; /* 0x51 */ + uint8_t rec_type; + uint8_t rec_length; +}; +#define IPMI_SDR_HEADER_SIZE sizeof(struct ipmi_sdr_header) + +#define ipmi_sdr_recid(sdr) ((sdr)->rec_id[0] | ((sdr)->rec_id[1] << 8)) +#define ipmi_sdr_length(sdr) ((sdr)->rec_length + IPMI_SDR_HEADER_SIZE) + +/* + * 43.2 SDR Type 02h. Compact Sensor Record + */ +#define IPMI_SDR_COMPACT_TYPE 2 + +struct ipmi_sdr_compact { + struct ipmi_sdr_header header; + + uint8_t sensor_owner_id; + uint8_t sensor_owner_lun; + uint8_t sensor_owner_number; /* byte 8 */ + uint8_t entity_id; + uint8_t entity_instance; + uint8_t sensor_init; + uint8_t sensor_caps; + uint8_t sensor_type; + uint8_t reading_type; + uint8_t assert_mask[2]; /* byte 16 */ + uint8_t deassert_mask[2]; + uint8_t discrete_mask[2]; + uint8_t sensor_unit1; + uint8_t sensor_unit2; + uint8_t sensor_unit3; + uint8_t sensor_direction[2]; /* byte 24 */ + uint8_t positive_threshold; + uint8_t negative_threshold; + uint8_t reserved[3]; + uint8_t oem; + uint8_t id_str_len; /* byte 32 */ + uint8_t id_string[16]; +}; + +typedef uint8_t ipmi_sdr_compact_buffer[sizeof(struct ipmi_sdr_compact)]; + #endif From 728710e1b02c5befaacfd58e5eb3c82c0cd3a31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:32 +0100 Subject: [PATCH 23/45] ipmi: add get and set SENSOR_TYPE commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Acked-by: Corey Minyard Reviewed-by: Greg Kurz Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 45 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 84fbcd2638..24a4b327f2 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -40,6 +40,8 @@ #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b #define IPMI_CMD_GET_SENSOR_READING 0x2d +#define IPMI_CMD_SET_SENSOR_TYPE 0x2e +#define IPMI_CMD_GET_SENSOR_TYPE 0x2f /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ @@ -1526,6 +1528,45 @@ static void get_sensor_reading(IPMIBmcSim *ibs, } } +static void set_sensor_type(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + IPMISensor *sens; + + + IPMI_CHECK_CMD_LEN(5); + if ((cmd[2] > MAX_SENSORS) || + !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { + rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; + return; + } + sens = ibs->sensors + cmd[2]; + sens->sensor_type = cmd[3]; + sens->evt_reading_type_code = cmd[4] & 0x7f; +} + +static void get_sensor_type(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + IPMISensor *sens; + + + IPMI_CHECK_CMD_LEN(3); + if ((cmd[2] > MAX_SENSORS) || + !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { + rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; + return; + } + sens = ibs->sensors + cmd[2]; + IPMI_ADD_RSP_DATA(sens->sensor_type); + IPMI_ADD_RSP_DATA(sens->evt_reading_type_code); +} + + static const IPMICmdHandler chassis_cmds[] = { [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, @@ -1541,7 +1582,9 @@ static const IPMICmdHandler sensor_event_cmds[] = { [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status, - [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading + [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading, + [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type, + [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type, }; static const IPMINetfn sensor_event_netfn = { .cmd_nums = ARRAY_SIZE(sensor_event_cmds), From b7088392239d0d6fd1140690a3efdb24df1bc7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:33 +0100 Subject: [PATCH 24/45] ipmi: add GET_SYS_RESTART_CAUSE chassis command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a simulator. Just return an unknown cause (0). Signed-off-by: Cédric Le Goater Acked-by: Corey Minyard Reviewed-by: Greg Kurz Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 24a4b327f2..29224ddd89 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -32,6 +32,7 @@ #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 #define IPMI_CMD_CHASSIS_CONTROL 0x02 +#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 #define IPMI_NETFN_SENSOR_EVENT 0x04 @@ -195,6 +196,8 @@ struct IPMIBmcSim { uint8_t mfg_id[3]; uint8_t product_id[2]; + uint8_t restart_cause; + IPMISel sel; IPMISdr sdr; IPMISensor sensors[MAX_SENSORS]; @@ -754,6 +757,15 @@ static void chassis_control(IPMIBmcSim *ibs, } } +static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */ + IPMI_ADD_RSP_DATA(0); /* Channel 0 */ +} + static void get_device_id(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, uint8_t *rsp, unsigned int *rsp_len, @@ -1570,7 +1582,8 @@ static void get_sensor_type(IPMIBmcSim *ibs, static const IPMICmdHandler chassis_cmds[] = { [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, - [IPMI_CMD_CHASSIS_CONTROL] = chassis_control + [IPMI_CMD_CHASSIS_CONTROL] = chassis_control, + [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause }; static const IPMINetfn chassis_netfn = { .cmd_nums = ARRAY_SIZE(chassis_cmds), @@ -1691,6 +1704,7 @@ static void ipmi_sim_init(Object *obj) ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); ibs->device_id = 0x20; ibs->ipmi_version = 0x02; /* IPMI 2.0 */ + ibs->restart_cause = 0; for (i = 0; i < 4; i++) { ibs->sel.last_addition[i] = 0xff; ibs->sel.last_clear[i] = 0xff; From 52ba4d509d1e5287bd8fdb477532713358887356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 25 Jan 2016 15:07:34 +0100 Subject: [PATCH 25/45] ipmi: add ACPI power and GUID commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit >From the specs (20.8 Get Device GUID Command), the command needs to return a GUID (Globally Unique ID), or UUID, that should never change over the lifetime of the device. qemu_uuid looked like a good candidate to start with but we could use a specific BMC property also if needed. Signed-off-by: Cédric Le Goater Acked-by: Corey Minyard Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 29224ddd89..e1ad19b8db 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "sysemu/sysemu.h" #include "qemu/timer.h" #include "hw/ipmi/ipmi.h" #include "qemu/error-report.h" @@ -49,6 +50,9 @@ #define IPMI_CMD_GET_DEVICE_ID 0x01 #define IPMI_CMD_COLD_RESET 0x02 #define IPMI_CMD_WARM_RESET 0x03 +#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 +#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 +#define IPMI_CMD_GET_DEVICE_GUID 0x08 #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 @@ -198,6 +202,9 @@ struct IPMIBmcSim { uint8_t restart_cause; + uint8_t acpi_power_state[2]; + uint8_t uuid[16]; + IPMISel sel; IPMISdr sdr; IPMISensor sensors[MAX_SENSORS]; @@ -826,6 +833,36 @@ static void warm_reset(IPMIBmcSim *ibs, k->reset(s, false); } } +static void set_acpi_power_state(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + IPMI_CHECK_CMD_LEN(4); + ibs->acpi_power_state[0] = cmd[2]; + ibs->acpi_power_state[1] = cmd[3]; +} + +static void get_acpi_power_state(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + IPMI_ADD_RSP_DATA(ibs->acpi_power_state[0]); + IPMI_ADD_RSP_DATA(ibs->acpi_power_state[1]); +} + +static void get_device_guid(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ + unsigned int i; + + for (i = 0; i < 16; i++) { + IPMI_ADD_RSP_DATA(ibs->uuid[i]); + } +} static void set_bmc_global_enables(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, @@ -1608,6 +1645,9 @@ static const IPMICmdHandler app_cmds[] = { [IPMI_CMD_GET_DEVICE_ID] = get_device_id, [IPMI_CMD_COLD_RESET] = cold_reset, [IPMI_CMD_WARM_RESET] = warm_reset, + [IPMI_CMD_SET_ACPI_POWER_STATE] = set_acpi_power_state, + [IPMI_CMD_GET_ACPI_POWER_STATE] = get_acpi_power_state, + [IPMI_CMD_GET_DEVICE_GUID] = get_device_guid, [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables, [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables, [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags, @@ -1733,6 +1773,15 @@ static void ipmi_sim_init(Object *obj) i += len; } + ibs->acpi_power_state[0] = 0; + ibs->acpi_power_state[1] = 0; + + if (qemu_uuid_set) { + memcpy(&ibs->uuid, qemu_uuid, 16); + } else { + memset(&ibs->uuid, 0, 16); + } + ipmi_init_sensors_from_sdrs(ibs); register_cmds(ibs); From 281b104702af40b08b29b621995830c0c0177a41 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:22 -0200 Subject: [PATCH 26/45] pc: Move PcGuestInfo declaration to top of file The struct will be used inside PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- include/hw/i386/pc.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 65e8f245a8..212eb7dcfa 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -33,6 +33,22 @@ #define kvm_ioapic_in_kernel() 0 #endif +/* Machine info for ACPI build: */ +struct PcGuestInfo { + bool isapc_ram_fw; + hwaddr ram_size, ram_size_below_4g; + unsigned apic_id_limit; + bool apic_xrupt_override; + uint64_t numa_nodes; + uint64_t *node_mem; + uint64_t *node_cpu; + FWCfgState *fw_cfg; + int legacy_acpi_table_size; + bool has_acpi_build; + bool has_reserved_memory; + bool rsdp_in_ram; +}; + /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling @@ -151,21 +167,6 @@ typedef struct PcPciInfo { #define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len" #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" -struct PcGuestInfo { - bool isapc_ram_fw; - hwaddr ram_size, ram_size_below_4g; - unsigned apic_id_limit; - bool apic_xrupt_override; - uint64_t numa_nodes; - uint64_t *node_mem; - uint64_t *node_cpu; - FWCfgState *fw_cfg; - int legacy_acpi_table_size; - bool has_acpi_build; - bool has_reserved_memory; - bool rsdp_in_ram; -}; - /* parallel.c */ void parallel_hds_isa_init(ISABus *bus, int n); From 9ebeed0c1efe4994c7c129e8469a797bcde9f81a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:23 -0200 Subject: [PATCH 27/45] pc: Eliminate struct PcGuestInfoState Instead of allocating a new struct just for PcGuestInfo and the mchine_done Notifier, place them inside PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 27 ++++++++++----------------- include/hw/i386/pc.h | 2 ++ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 942ac0659a..c421d2c30d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1156,18 +1156,12 @@ typedef struct PcRomPciInfo { uint64_t w64_max; } PcRomPciInfo; -typedef struct PcGuestInfoState { - PcGuestInfo info; - Notifier machine_done; -} PcGuestInfoState; - static -void pc_guest_info_machine_done(Notifier *notifier, void *data) +void pc_machine_done(Notifier *notifier, void *data) { - PcGuestInfoState *guest_info_state = container_of(notifier, - PcGuestInfoState, - machine_done); - PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; + PCMachineState *pcms = container_of(notifier, + PCMachineState, machine_done); + PCIBus *bus = pcms->bus; if (bus) { int extra_hosts = 0; @@ -1178,21 +1172,20 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data) extra_hosts++; } } - if (extra_hosts && guest_info_state->info.fw_cfg) { + if (extra_hosts && pcms->acpi_guest_info.fw_cfg) { uint64_t *val = g_malloc(sizeof(*val)); *val = cpu_to_le64(extra_hosts); - fw_cfg_add_file(guest_info_state->info.fw_cfg, + fw_cfg_add_file(pcms->acpi_guest_info.fw_cfg, "etc/extra-pci-roots", val, sizeof(*val)); } } - acpi_setup(&guest_info_state->info); + acpi_setup(&pcms->acpi_guest_info); } PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) { - PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); - PcGuestInfo *guest_info = &guest_info_state->info; + PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; guest_info->ram_size_below_4g = pcms->below_4g_mem_size; @@ -1220,8 +1213,8 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) } } - guest_info_state->machine_done.notify = pc_guest_info_machine_done; - qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); + pcms->machine_done.notify = pc_machine_done; + qemu_add_machine_init_done_notifier(&pcms->machine_done); return guest_info; } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 212eb7dcfa..9d0b004d74 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -61,6 +61,8 @@ struct PCMachineState { /* State for other subsystems/APIs: */ MemoryHotplugState hotplug_memory; + PcGuestInfo acpi_guest_info; + Notifier machine_done; /* Pointers to devices and objects: */ HotplugHandler *acpi_dev; From 5934e2169a383cdb059f8ccd83f7e1c4d410c9b3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:24 -0200 Subject: [PATCH 28/45] pc: Simplify pc_memory_init() signature We can get the PcGuestInfo struct directly from PCMachineState, and the return value is not needed at all. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 11 +++++------ hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 9 ++++----- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c421d2c30d..fbdad8813f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1276,12 +1276,12 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, return fw_cfg; } -FWCfgState *pc_memory_init(PCMachineState *pcms, - MemoryRegion *system_memory, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory, - PcGuestInfo *guest_info) +void pc_memory_init(PCMachineState *pcms, + MemoryRegion *system_memory, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory) { + PcGuestInfo *guest_info = &pcms->acpi_guest_info; int linux_boot, i; MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; @@ -1403,7 +1403,6 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, rom_add_option(option_rom[i].name, option_rom[i].bootindex); } guest_info->fw_cfg = fw_cfg; - return fw_cfg; } qemu_irq pc_allocate_cpu_irq(void) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9951d6e1d5..ad51fd674b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -162,7 +162,7 @@ static void pc_init1(MachineState *machine, /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, system_memory, - rom_memory, &ram_memory, guest_info); + rom_memory, &ram_memory); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ xen_load_linux(pcms, guest_info); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 56be9b1d16..0c156e21b6 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -156,7 +156,7 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, get_system_memory(), - rom_memory, &ram_memory, guest_info); + rom_memory, &ram_memory); } /* irq lines */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9d0b004d74..5b21d0120d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -250,11 +250,10 @@ void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info); -FWCfgState *pc_memory_init(PCMachineState *pcms, - MemoryRegion *system_memory, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory, - PcGuestInfo *guest_info); +void pc_memory_init(PCMachineState *pcms, + MemoryRegion *system_memory, + MemoryRegion *rom_memory, + MemoryRegion **ram_memory); qemu_irq pc_allocate_cpu_irq(void); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, From 7bc35e0f20a1e6f1b00edc85618437a495873bbd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:25 -0200 Subject: [PATCH 29/45] pc: Simplify xen_load_linux() signature We can get the PcGuestInfo struct directly from PCMachineState, and the return value is not needed at all. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 5 ++--- hw/i386/pc_piix.c | 2 +- include/hw/i386/pc.h | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fbdad8813f..9745dcaec4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1255,11 +1255,11 @@ void pc_acpi_init(const char *default_dsdt) } } -FWCfgState *xen_load_linux(PCMachineState *pcms, - PcGuestInfo *guest_info) +void xen_load_linux(PCMachineState *pcms) { int i; FWCfgState *fw_cfg; + PcGuestInfo *guest_info = &pcms->acpi_guest_info; assert(MACHINE(pcms)->kernel_filename != NULL); @@ -1273,7 +1273,6 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, rom_add_option(option_rom[i].name, option_rom[i].bootindex); } guest_info->fw_cfg = fw_cfg; - return fw_cfg; } void pc_memory_init(PCMachineState *pcms, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ad51fd674b..4262c32575 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -165,7 +165,7 @@ static void pc_init1(MachineState *machine, rom_memory, &ram_memory); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ - xen_load_linux(pcms, guest_info); + xen_load_linux(pcms); } gsi_state = g_malloc0(sizeof(*gsi_state)); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 5b21d0120d..223621a30c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -248,8 +248,7 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, MemoryRegion *pci_address_space); -FWCfgState *xen_load_linux(PCMachineState *pcms, - PcGuestInfo *guest_info); +void xen_load_linux(PCMachineState *pcms); void pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, MemoryRegion *rom_memory, From fb306ffeba87f36d630ab2f1684ca39f93547e0a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:26 -0200 Subject: [PATCH 30/45] acpi: Remove guest_info parameters from functions We can use PC_MACHINE(qdev_get_machine())->acpi_guest_info to get guest_info. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2028ed78da..e41a2ae6a7 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -290,7 +290,7 @@ static void acpi_align_size(GArray *blob, unsigned align) /* FACS */ static void -build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) +build_facs(GArray *table_data, GArray *linker) { AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs); memcpy(&facs->signature, "FACS", 4); @@ -361,9 +361,10 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, } static void -build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, - PcGuestInfo *guest_info) +build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) { + PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PcGuestInfo *guest_info = &pcms->acpi_guest_info; int madt_start = table_data->len; AcpiMultipleApicTable *madt; @@ -1937,13 +1938,15 @@ static Aml *build_q35_osc_method(void) static void build_dsdt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc, - PcPciInfo *pci, PcGuestInfo *guest_info) + PcPciInfo *pci) { CrsRangeEntry *entry; Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); MachineState *machine = MACHINE(qdev_get_machine()); + PCMachineState *pcms = PC_MACHINE(machine); + PcGuestInfo *guest_info = &pcms->acpi_guest_info; uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; @@ -2365,7 +2368,7 @@ acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, } static void -build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) +build_srat(GArray *table_data, GArray *linker) { AcpiSystemResourceAffinityTable *srat; AcpiSratProcessorAffinity *core; @@ -2376,6 +2379,7 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) int srat_start, numa_start, slots; uint64_t mem_len, mem_base, next_base; PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PcGuestInfo *guest_info = &pcms->acpi_guest_info; ram_addr_t hotplugabble_address_space_size = object_property_get_int(OBJECT(pcms), PC_MACHINE_MEMHP_REGION_SIZE, NULL); @@ -2587,8 +2591,10 @@ static bool acpi_has_nvdimm(void) } static -void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) +void acpi_build(AcpiBuildTables *tables) { + PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PcGuestInfo *guest_info = &pcms->acpi_guest_info; GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; AcpiCpuInfo cpu; @@ -2619,12 +2625,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) * requirements. */ facs = tables_blob->len; - build_facs(tables_blob, tables->linker, guest_info); + build_facs(tables_blob, tables->linker); /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci, - guest_info); + build_dsdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci); /* Count the size of the DSDT and SSDT, we will need it for legacy * sizing of ACPI tables. @@ -2638,7 +2643,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, &cpu, guest_info); + build_madt(tables_blob, tables->linker, &cpu); if (misc.has_hpet) { acpi_add_table(table_offsets, tables_blob); @@ -2655,7 +2660,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) } if (guest_info->numa_nodes) { acpi_add_table(table_offsets, tables_blob); - build_srat(tables_blob, tables->linker, guest_info); + build_srat(tables_blob, tables->linker); } if (acpi_get_mcfg(&mcfg)) { acpi_add_table(table_offsets, tables_blob); @@ -2759,7 +2764,7 @@ static void acpi_build_update(void *build_opaque) acpi_build_tables_init(&tables); - acpi_build(build_state->guest_info, &tables); + acpi_build(&tables); acpi_ram_update(build_state->table_mr, tables.table_data); @@ -2797,8 +2802,10 @@ static const VMStateDescription vmstate_acpi_build = { }, }; -void acpi_setup(PcGuestInfo *guest_info) +void acpi_setup(void) { + PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PcGuestInfo *guest_info = &pcms->acpi_guest_info; AcpiBuildTables tables; AcpiBuildState *build_state; @@ -2824,7 +2831,7 @@ void acpi_setup(PcGuestInfo *guest_info) acpi_set_pci_info(); acpi_build_tables_init(&tables); - acpi_build(build_state->guest_info, &tables); + acpi_build(&tables); /* Now expose it all to Guest */ build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data, From f944d4798c4e8ebb85161d81431d3457de36d042 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:27 -0200 Subject: [PATCH 31/45] acpi: Don't save PcGuestInfo on AcpiBuildState We don't need to save the pointer on AcpiBuildState, as it is not used anymore. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index e41a2ae6a7..45c07caed4 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2545,7 +2545,6 @@ struct AcpiBuildState { MemoryRegion *table_mr; /* Is table patched? */ uint8_t patched; - PcGuestInfo *guest_info; void *rsdp; MemoryRegion *rsdp_mr; MemoryRegion *linker_mr; @@ -2826,8 +2825,6 @@ void acpi_setup(void) build_state = g_malloc0(sizeof *build_state); - build_state->guest_info = guest_info; - acpi_set_pci_info(); acpi_build_tables_init(&tables); From bb292f5a9b944e47fae88a20767967e7e20122b4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:28 -0200 Subject: [PATCH 32/45] pc: Remove compat fields from PcGuestInfo Remove the fields: legacy_acpi_table_size, has_acpi_build, has_reserved_memory, and rsdp_in_ram from PcGuestInfo, and let the existing code use the PCMachineClass fields directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 10 ++++++---- hw/i386/acpi-build.h | 2 +- hw/i386/pc.c | 8 ++++---- hw/i386/pc_piix.c | 5 ----- hw/i386/pc_q35.c | 8 -------- include/hw/i386/pc.h | 4 ---- 6 files changed, 11 insertions(+), 26 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 45c07caed4..7f574f28c3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2593,6 +2593,7 @@ static void acpi_build(AcpiBuildTables *tables) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); PcGuestInfo *guest_info = &pcms->acpi_guest_info; GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; @@ -2706,12 +2707,12 @@ void acpi_build(AcpiBuildTables *tables) * * All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration. */ - if (guest_info->legacy_acpi_table_size) { + if (pcmc->legacy_acpi_table_size) { /* Subtracting aml_len gives the size of fixed tables. Then add the * size of the PIIX4 DSDT/SSDT in QEMU 2.0. */ int legacy_aml_len = - guest_info->legacy_acpi_table_size + + pcmc->legacy_acpi_table_size + ACPI_BUILD_LEGACY_CPU_AML_SIZE * max_cpus; int legacy_table_size = ROUND_UP(tables_blob->len - aml_len + legacy_aml_len, @@ -2804,6 +2805,7 @@ static const VMStateDescription vmstate_acpi_build = { void acpi_setup(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); PcGuestInfo *guest_info = &pcms->acpi_guest_info; AcpiBuildTables tables; AcpiBuildState *build_state; @@ -2813,7 +2815,7 @@ void acpi_setup(void) return; } - if (!guest_info->has_acpi_build) { + if (!pcmc->has_acpi_build) { ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); return; } @@ -2842,7 +2844,7 @@ void acpi_setup(void) fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); - if (!guest_info->rsdp_in_ram) { + if (!pcmc->rsdp_in_ram) { /* * Keep for compatibility with old machine types. * Though RSDP is small, its contents isn't immutable, so diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h index e57b1aafdc..148c0f9977 100644 --- a/hw/i386/acpi-build.h +++ b/hw/i386/acpi-build.h @@ -4,6 +4,6 @@ #include "qemu/typedefs.h" -void acpi_setup(PcGuestInfo *); +void acpi_setup(void); #endif diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 9745dcaec4..3c59500d84 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1180,7 +1180,7 @@ void pc_machine_done(Notifier *notifier, void *data) } } - acpi_setup(&pcms->acpi_guest_info); + acpi_setup(); } PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) @@ -1316,7 +1316,7 @@ void pc_memory_init(PCMachineState *pcms, e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM); } - if (!guest_info->has_reserved_memory && + if (!pcmc->has_reserved_memory && (machine->ram_slots || (machine->maxram_size > machine->ram_size))) { MachineClass *mc = MACHINE_GET_CLASS(machine); @@ -1327,7 +1327,7 @@ void pc_memory_init(PCMachineState *pcms, } /* initialize hotplug memory address space */ - if (guest_info->has_reserved_memory && + if (pcmc->has_reserved_memory && (machine->ram_size < machine->maxram_size)) { ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size; @@ -1382,7 +1382,7 @@ void pc_memory_init(PCMachineState *pcms, rom_set_fw(fw_cfg); - if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) { + if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) { uint64_t *val = g_malloc(sizeof(*val)); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); uint64_t res_mem_end = pcms->hotplug_memory.base; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4262c32575..584441a832 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -143,12 +143,7 @@ static void pc_init1(MachineState *machine, guest_info = pc_guest_info_init(pcms); - guest_info->has_acpi_build = pcmc->has_acpi_build; - guest_info->legacy_acpi_table_size = pcmc->legacy_acpi_table_size; - guest_info->isapc_ram_fw = !pcmc->pci_enabled; - guest_info->has_reserved_memory = pcmc->has_reserved_memory; - guest_info->rsdp_in_ram = pcmc->rsdp_in_ram; if (pcmc->smbios_defaults) { MachineClass *mc = MACHINE_GET_CLASS(machine); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0c156e21b6..45e05f4a03 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -136,14 +136,6 @@ static void pc_q35_init(MachineState *machine) guest_info = pc_guest_info_init(pcms); guest_info->isapc_ram_fw = false; - guest_info->has_acpi_build = pcmc->has_acpi_build; - guest_info->has_reserved_memory = pcmc->has_reserved_memory; - guest_info->rsdp_in_ram = pcmc->rsdp_in_ram; - - /* Migration was not supported in 2.0 for Q35, so do not bother - * with this hack (see hw/i386/acpi-build.c). - */ - guest_info->legacy_acpi_table_size = 0; if (pcmc->smbios_defaults) { /* These values are guest ABI, do not change */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 223621a30c..4480409e77 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -43,10 +43,6 @@ struct PcGuestInfo { uint64_t *node_mem; uint64_t *node_cpu; FWCfgState *fw_cfg; - int legacy_acpi_table_size; - bool has_acpi_build; - bool has_reserved_memory; - bool rsdp_in_ram; }; /** From 5299f1c70aa7ebc89383363cd3d47fc4f5dc2163 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:29 -0200 Subject: [PATCH 33/45] pc: Remove RAM size fields from PcGuestInfo The ACPI code can use the PCMachineState fields directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 10 +++++----- hw/i386/pc.c | 2 -- include/hw/i386/pc.h | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 7f574f28c3..dac7137471 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2421,17 +2421,17 @@ build_srat(GArray *table_data, GArray *linker) next_base = mem_base + mem_len; /* Cut out the ACPI_PCI hole */ - if (mem_base <= guest_info->ram_size_below_4g && - next_base > guest_info->ram_size_below_4g) { - mem_len -= next_base - guest_info->ram_size_below_4g; + if (mem_base <= pcms->below_4g_mem_size && + next_base > pcms->below_4g_mem_size) { + mem_len -= next_base - pcms->below_4g_mem_size; if (mem_len > 0) { numamem = acpi_data_push(table_data, sizeof *numamem); acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1, MEM_AFFINITY_ENABLED); } mem_base = 1ULL << 32; - mem_len = next_base - guest_info->ram_size_below_4g; - next_base += (1ULL << 32) - guest_info->ram_size_below_4g; + mem_len = next_base - pcms->below_4g_mem_size; + next_base += (1ULL << 32) - pcms->below_4g_mem_size; } numamem = acpi_data_push(table_data, sizeof *numamem); acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3c59500d84..f3fd0ed47c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1188,8 +1188,6 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; - guest_info->ram_size_below_4g = pcms->below_4g_mem_size; - guest_info->ram_size = pcms->below_4g_mem_size + pcms->above_4g_mem_size; guest_info->apic_id_limit = pc_apic_id_limit(max_cpus); guest_info->apic_xrupt_override = kvm_allows_irq0_override(); guest_info->numa_nodes = nb_numa_nodes; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4480409e77..c27e680ee0 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -36,7 +36,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { bool isapc_ram_fw; - hwaddr ram_size, ram_size_below_4g; unsigned apic_id_limit; bool apic_xrupt_override; uint64_t numa_nodes; From 5db3f0deaf165bd0ff247fcea042cb2e60671e43 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:30 -0200 Subject: [PATCH 34/45] pc: Remove PcGuestInfo.isapc_ram_fw field The code can use the PCMachineClass.pci_enabled field directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 2 +- hw/i386/pc_piix.c | 5 +---- hw/i386/pc_q35.c | 4 +--- include/hw/i386/pc.h | 1 - 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f3fd0ed47c..dc0ade4a8c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1365,7 +1365,7 @@ void pc_memory_init(PCMachineState *pcms, } /* Initialize PC system firmware */ - pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw); + pc_system_firmware_init(rom_memory, !pcmc->pci_enabled); option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 584441a832..6f8c2cd816 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -85,7 +85,6 @@ static void pc_init1(MachineState *machine, MemoryRegion *ram_memory; MemoryRegion *pci_memory; MemoryRegion *rom_memory; - PcGuestInfo *guest_info; ram_addr_t lowmem; /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory). @@ -141,9 +140,7 @@ static void pc_init1(MachineState *machine, rom_memory = system_memory; } - guest_info = pc_guest_info_init(pcms); - - guest_info->isapc_ram_fw = !pcmc->pci_enabled; + pc_guest_info_init(pcms); if (pcmc->smbios_defaults) { MachineClass *mc = MACHINE_GET_CLASS(machine); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 45e05f4a03..208a224226 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -71,7 +71,6 @@ static void pc_q35_init(MachineState *machine) int i; ICH9LPCState *ich9_lpc; PCIDevice *ahci; - PcGuestInfo *guest_info; ram_addr_t lowmem; DriveInfo *hd[MAX_SATA_PORTS]; MachineClass *mc = MACHINE_GET_CLASS(machine); @@ -134,8 +133,7 @@ static void pc_q35_init(MachineState *machine) rom_memory = get_system_memory(); } - guest_info = pc_guest_info_init(pcms); - guest_info->isapc_ram_fw = false; + pc_guest_info_init(pcms); if (pcmc->smbios_defaults) { /* These values are guest ABI, do not change */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c27e680ee0..6a5c4da053 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,7 +35,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { - bool isapc_ram_fw; unsigned apic_id_limit; bool apic_xrupt_override; uint64_t numa_nodes; From f264d360e0bebf4fae054e624bf7204788aff99d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:31 -0200 Subject: [PATCH 35/45] pc: Move PcGuestInfo.fw_cfg to PCMachineState Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 7 +++---- hw/i386/pc.c | 10 ++++------ include/hw/i386/pc.h | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dac7137471..86baf63a1d 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2806,11 +2806,10 @@ void acpi_setup(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; AcpiBuildTables tables; AcpiBuildState *build_state; - if (!guest_info->fw_cfg) { + if (!pcms->fw_cfg) { ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); return; } @@ -2841,7 +2840,7 @@ void acpi_setup(void) build_state->linker_mr = acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0); - fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, + fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); if (!pcmc->rsdp_in_ram) { @@ -2853,7 +2852,7 @@ void acpi_setup(void) uint32_t rsdp_size = acpi_data_len(tables.rsdp); build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size); - fw_cfg_add_file_callback(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE, + fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE, acpi_build_update, build_state, build_state->rsdp, rsdp_size); build_state->rsdp_mr = NULL; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index dc0ade4a8c..a47784a38e 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1172,10 +1172,10 @@ void pc_machine_done(Notifier *notifier, void *data) extra_hosts++; } } - if (extra_hosts && pcms->acpi_guest_info.fw_cfg) { + if (extra_hosts && pcms->fw_cfg) { uint64_t *val = g_malloc(sizeof(*val)); *val = cpu_to_le64(extra_hosts); - fw_cfg_add_file(pcms->acpi_guest_info.fw_cfg, + fw_cfg_add_file(pcms->fw_cfg, "etc/extra-pci-roots", val, sizeof(*val)); } } @@ -1257,7 +1257,6 @@ void xen_load_linux(PCMachineState *pcms) { int i; FWCfgState *fw_cfg; - PcGuestInfo *guest_info = &pcms->acpi_guest_info; assert(MACHINE(pcms)->kernel_filename != NULL); @@ -1270,7 +1269,7 @@ void xen_load_linux(PCMachineState *pcms) !strcmp(option_rom[i].name, "multiboot.bin")); rom_add_option(option_rom[i].name, option_rom[i].bootindex); } - guest_info->fw_cfg = fw_cfg; + pcms->fw_cfg = fw_cfg; } void pc_memory_init(PCMachineState *pcms, @@ -1278,7 +1277,6 @@ void pc_memory_init(PCMachineState *pcms, MemoryRegion *rom_memory, MemoryRegion **ram_memory) { - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int linux_boot, i; MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; @@ -1399,7 +1397,7 @@ void pc_memory_init(PCMachineState *pcms, for (i = 0; i < nb_option_roms; i++) { rom_add_option(option_rom[i].name, option_rom[i].bootindex); } - guest_info->fw_cfg = fw_cfg; + pcms->fw_cfg = fw_cfg; } qemu_irq pc_allocate_cpu_irq(void) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 6a5c4da053..40249b6b02 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -40,7 +40,6 @@ struct PcGuestInfo { uint64_t numa_nodes; uint64_t *node_mem; uint64_t *node_cpu; - FWCfgState *fw_cfg; }; /** @@ -62,6 +61,7 @@ struct PCMachineState { HotplugHandler *acpi_dev; ISADevice *rtc; PCIBus *bus; + FWCfgState *fw_cfg; /* Configuration options: */ uint64_t max_ram_below_4g; From dd4c2f01ab92ae0a158958a8fc61fcd09e34987a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:32 -0200 Subject: [PATCH 36/45] pc: Move APIC and NUMA data from PcGuestInfo to PCMachineState Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 22 +++++++++------------- hw/i386/pc.c | 20 ++++++++++---------- include/hw/i386/pc.h | 14 +++++++++----- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 86baf63a1d..35582a761d 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -364,7 +364,6 @@ static void build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int madt_start = table_data->len; AcpiMultipleApicTable *madt; @@ -377,7 +376,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS); madt->flags = cpu_to_le32(1); - for (i = 0; i < guest_info->apic_id_limit; i++) { + for (i = 0; i < pcms->apic_id_limit; i++) { AcpiMadtProcessorApic *apic = acpi_data_push(table_data, sizeof *apic); apic->type = ACPI_APIC_PROCESSOR; apic->length = sizeof(*apic); @@ -397,7 +396,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); io_apic->interrupt = cpu_to_le32(0); - if (guest_info->apic_xrupt_override) { + if (pcms->apic_xrupt_override) { intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr); intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; intsrcovr->length = sizeof(*intsrcovr); @@ -1946,7 +1945,6 @@ build_dsdt(GArray *table_data, GArray *linker, GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); MachineState *machine = MACHINE(qdev_get_machine()); PCMachineState *pcms = PC_MACHINE(machine); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; @@ -2247,7 +2245,7 @@ build_dsdt(GArray *table_data, GArray *linker, sb_scope = aml_scope("\\_SB"); { - build_processor_devices(sb_scope, guest_info->apic_id_limit, cpu, pm); + build_processor_devices(sb_scope, pcms->apic_id_limit, cpu, pm); build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base, pm->mem_hp_io_len); @@ -2379,7 +2377,6 @@ build_srat(GArray *table_data, GArray *linker) int srat_start, numa_start, slots; uint64_t mem_len, mem_base, next_base; PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; ram_addr_t hotplugabble_address_space_size = object_property_get_int(OBJECT(pcms), PC_MACHINE_MEMHP_REGION_SIZE, NULL); @@ -2390,12 +2387,12 @@ build_srat(GArray *table_data, GArray *linker) srat->reserved1 = cpu_to_le32(1); core = (void *)(srat + 1); - for (i = 0; i < guest_info->apic_id_limit; ++i) { + for (i = 0; i < pcms->apic_id_limit; ++i) { core = acpi_data_push(table_data, sizeof *core); core->type = ACPI_SRAT_PROCESSOR; core->length = sizeof(*core); core->local_apic_id = i; - curnode = guest_info->node_cpu[i]; + curnode = pcms->node_cpu[i]; core->proximity_lo = curnode; memset(core->proximity_hi, 0, 3); core->local_sapic_eid = 0; @@ -2412,9 +2409,9 @@ build_srat(GArray *table_data, GArray *linker) numamem = acpi_data_push(table_data, sizeof *numamem); acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED); next_base = 1024 * 1024; - for (i = 1; i < guest_info->numa_nodes + 1; ++i) { + for (i = 1; i < pcms->numa_nodes + 1; ++i) { mem_base = next_base; - mem_len = guest_info->node_mem[i - 1]; + mem_len = pcms->node_mem[i - 1]; if (i == 1) { mem_len -= 1024 * 1024; } @@ -2438,7 +2435,7 @@ build_srat(GArray *table_data, GArray *linker) MEM_AFFINITY_ENABLED); } slots = (table_data->len - numa_start) / sizeof *numamem; - for (; slots < guest_info->numa_nodes + 2; slots++) { + for (; slots < pcms->numa_nodes + 2; slots++) { numamem = acpi_data_push(table_data, sizeof *numamem); acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); } @@ -2594,7 +2591,6 @@ void acpi_build(AcpiBuildTables *tables) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; AcpiCpuInfo cpu; @@ -2658,7 +2654,7 @@ void acpi_build(AcpiBuildTables *tables) build_tpm2(tables_blob, tables->linker); } } - if (guest_info->numa_nodes) { + if (pcms->numa_nodes) { acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a47784a38e..66f7bb9bc0 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1188,24 +1188,24 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; - guest_info->apic_id_limit = pc_apic_id_limit(max_cpus); - guest_info->apic_xrupt_override = kvm_allows_irq0_override(); - guest_info->numa_nodes = nb_numa_nodes; - guest_info->node_mem = g_malloc0(guest_info->numa_nodes * - sizeof *guest_info->node_mem); + pcms->apic_id_limit = pc_apic_id_limit(max_cpus); + pcms->apic_xrupt_override = kvm_allows_irq0_override(); + pcms->numa_nodes = nb_numa_nodes; + pcms->node_mem = g_malloc0(pcms->numa_nodes * + sizeof *pcms->node_mem); for (i = 0; i < nb_numa_nodes; i++) { - guest_info->node_mem[i] = numa_info[i].node_mem; + pcms->node_mem[i] = numa_info[i].node_mem; } - guest_info->node_cpu = g_malloc0(guest_info->apic_id_limit * - sizeof *guest_info->node_cpu); + pcms->node_cpu = g_malloc0(pcms->apic_id_limit * + sizeof *pcms->node_cpu); for (i = 0; i < max_cpus; i++) { unsigned int apic_id = x86_cpu_apic_id_from_index(i); - assert(apic_id < guest_info->apic_id_limit); + assert(apic_id < pcms->apic_id_limit); for (j = 0; j < nb_numa_nodes; j++) { if (test_bit(i, numa_info[j].node_cpu)) { - guest_info->node_cpu[apic_id] = j; + pcms->node_cpu[apic_id] = j; break; } } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 40249b6b02..0cf67ed6f3 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,11 +35,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { - unsigned apic_id_limit; - bool apic_xrupt_override; - uint64_t numa_nodes; - uint64_t *node_mem; - uint64_t *node_cpu; }; /** @@ -71,6 +66,15 @@ struct PCMachineState { /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; + + /* CPU and apic information: */ + bool apic_xrupt_override; + unsigned apic_id_limit; + + /* NUMA information: */ + uint64_t numa_nodes; + uint64_t *node_mem; + uint64_t *node_cpu; }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" From e4e8ba04c2007d3d05d8a29857f95ae80951f5a3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:33 -0200 Subject: [PATCH 37/45] pc: Eliminate PcGuestInfo struct The struct is not used for anything, now. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 4 +--- include/hw/i386/pc.h | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 66f7bb9bc0..ce185bbee9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1183,9 +1183,8 @@ void pc_machine_done(Notifier *notifier, void *data) acpi_setup(); } -PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) +void pc_guest_info_init(PCMachineState *pcms) { - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; pcms->apic_id_limit = pc_apic_id_limit(max_cpus); @@ -1213,7 +1212,6 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) pcms->machine_done.notify = pc_machine_done; qemu_add_machine_init_done_notifier(&pcms->machine_done); - return guest_info; } /* setup pci memory address space mapping into system address space */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0cf67ed6f3..8b3546ed5c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -33,10 +33,6 @@ #define kvm_ioapic_in_kernel() 0 #endif -/* Machine info for ACPI build: */ -struct PcGuestInfo { -}; - /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling @@ -49,7 +45,6 @@ struct PCMachineState { /* State for other subsystems/APIs: */ MemoryHotplugState hotplug_memory; - PcGuestInfo acpi_guest_info; Notifier machine_done; /* Pointers to devices and objects: */ @@ -233,7 +228,7 @@ void pc_cpus_init(PCMachineState *pcms); void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); -PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); +void pc_guest_info_init(PCMachineState *pcms); #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" #define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" From 37ad223c515da2fe9f1c679768cb5ccaa42e57e1 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:10 +0100 Subject: [PATCH 38/45] acpi: take oem_id in build_header(), optionally This patch is the continuation of commit 8870ca0e94f2 ("acpi: support specified oem table id for build_header"). It will allow us to control the OEM ID field too in the SDT header. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Xiao Guangrong (maintainer:NVDIMM) Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) Cc: Paolo Bonzini (maintainer:X86) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Shannon Zhao --- hw/acpi/aml-build.c | 11 ++++++++--- hw/acpi/nvdimm.c | 4 ++-- hw/arm/virt-acpi-build.c | 12 ++++++------ hw/i386/acpi-build.c | 18 +++++++++--------- include/hw/acpi/aml-build.h | 2 +- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 21d2ea0c9c..e4b6c0caa9 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1426,12 +1426,17 @@ Aml *aml_alias(const char *source_object, const char *alias_object) void build_header(GArray *linker, GArray *table_data, AcpiTableHeader *h, const char *sig, int len, uint8_t rev, - const char *oem_table_id) + const char *oem_id, const char *oem_table_id) { memcpy(&h->signature, sig, 4); h->length = cpu_to_le32(len); h->revision = rev; - memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); + + if (oem_id) { + strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id); + } else { + memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); + } if (oem_table_id) { strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id)); @@ -1506,5 +1511,5 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) sizeof(uint32_t)); } build_header(linker, table_data, - (void *)rsdt, "RSDT", rsdt_len, 1, NULL); + (void *)rsdt, "RSDT", rsdt_len, 1, NULL, NULL); } diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 7ee7e1623c..49ee68e614 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -366,7 +366,7 @@ static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets, build_header(linker, table_data, (void *)(table_data->data + header), "NFIT", - sizeof(NvdimmNfitHeader) + structures->len, 1, NULL); + sizeof(NvdimmNfitHeader) + structures->len, 1, NULL, NULL); g_array_free(structures, true); } @@ -471,7 +471,7 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len); build_header(linker, table_data, (void *)(table_data->data + table_data->len - ssdt->buf->len), - "SSDT", ssdt->buf->len, 1, "NVDIMM"); + "SSDT", ssdt->buf->len, 1, NULL, "NVDIMM"); free_aml_allocator(); } diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 87fbe7c97d..8017b12e6c 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -408,7 +408,7 @@ build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2, - NULL); + NULL, NULL); } static void @@ -427,7 +427,7 @@ build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN) - 1; - build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL); + build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL); } /* GTDT */ @@ -453,7 +453,7 @@ build_gtdt(GArray *table_data, GArray *linker) build_header(linker, table_data, (void *)(table_data->data + gtdt_start), "GTDT", - table_data->len - gtdt_start, 2, NULL); + table_data->len - gtdt_start, 2, NULL, NULL); } /* MADT */ @@ -515,7 +515,7 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info, build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 3, NULL); + table_data->len - madt_start, 3, NULL, NULL); } /* FADT */ @@ -540,7 +540,7 @@ build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) sizeof fadt->dsdt); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 5, NULL); + (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); } /* DSDT */ @@ -579,7 +579,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); build_header(linker, table_data, (void *)(table_data->data + table_data->len - dsdt->buf->len), - "DSDT", dsdt->buf->len, 2, NULL); + "DSDT", dsdt->buf->len, 2, NULL, NULL); free_aml_allocator(); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 35582a761d..061a9cbb21 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -357,7 +357,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, fadt_setup(fadt, pm); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 1, NULL); + (void *)fadt, "FACP", sizeof(*fadt), 1, NULL, NULL); } static void @@ -427,7 +427,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 1, NULL); + table_data->len - madt_start, 1, NULL, NULL); } /* Assign BSEL property to all buses. In the future, this can be changed @@ -2286,7 +2286,7 @@ build_dsdt(GArray *table_data, GArray *linker, g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); build_header(linker, table_data, (void *)(table_data->data + table_data->len - dsdt->buf->len), - "DSDT", dsdt->buf->len, 1, NULL); + "DSDT", dsdt->buf->len, 1, NULL, NULL); free_aml_allocator(); } @@ -2302,7 +2302,7 @@ build_hpet(GArray *table_data, GArray *linker) hpet->timer_block_id = cpu_to_le32(0x8086a201); hpet->addr.address = cpu_to_le64(HPET_BASE); build_header(linker, table_data, - (void *)hpet, "HPET", sizeof(*hpet), 1, NULL); + (void *)hpet, "HPET", sizeof(*hpet), 1, NULL, NULL); } static void @@ -2325,7 +2325,7 @@ build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog) sizeof(tcpa->log_area_start_address)); build_header(linker, table_data, - (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL); + (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL); acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); } @@ -2342,7 +2342,7 @@ build_tpm2(GArray *table_data, GArray *linker) tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); build_header(linker, table_data, - (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL); + (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); } typedef enum { @@ -2456,7 +2456,7 @@ build_srat(GArray *table_data, GArray *linker) build_header(linker, table_data, (void *)(table_data->data + srat_start), "SRAT", - table_data->len - srat_start, 1, NULL); + table_data->len - srat_start, 1, NULL, NULL); } static void @@ -2485,7 +2485,7 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) } else { sig = "MCFG"; } - build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL); + build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL); } static void @@ -2509,7 +2509,7 @@ build_dmar_q35(GArray *table_data, GArray *linker) drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR); build_header(linker, table_data, (void *)(table_data->data + dmar_start), - "DMAR", table_data->len - dmar_start, 1, NULL); + "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } static GArray * diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 6d6f705b0c..c460bdd255 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -357,7 +357,7 @@ Aml *aml_sizeof(Aml *arg); void build_header(GArray *linker, GArray *table_data, AcpiTableHeader *h, const char *sig, int len, uint8_t rev, - const char *oem_table_id); + const char *oem_id, const char *oem_table_id); void *acpi_data_push(GArray *table_data, unsigned size); unsigned acpi_data_len(GArray *table); void acpi_add_table(GArray *table_offsets, GArray *table_data); From 5151355898699eb66fad0a710b8b6011690a0dfc Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:11 +0100 Subject: [PATCH 39/45] acpi: expose oem_id and oem_table_id in build_rsdt() Since build_rsdt() is implemented as common utility code (in "hw/acpi/aml-build.c"), it should expose -- and forward -- the oem_id and oem_table_id parameters between board code and the generic build_header() function. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) Cc: Paolo Bonzini (maintainer:X86) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Shannon Zhao --- hw/acpi/aml-build.c | 5 +++-- hw/arm/virt-acpi-build.c | 2 +- hw/i386/acpi-build.c | 2 +- include/hw/acpi/aml-build.h | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index e4b6c0caa9..603068b5ea 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1492,7 +1492,8 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) /* Build rsdt table */ void -build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) +build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, + const char *oem_id, const char *oem_table_id) { AcpiRsdtDescriptorRev1 *rsdt; size_t rsdt_len; @@ -1511,5 +1512,5 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) sizeof(uint32_t)); } build_header(linker, table_data, - (void *)rsdt, "RSDT", rsdt_len, 1, NULL, NULL); + (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); } diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 8017b12e6c..560764fab1 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -643,7 +643,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets); + build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 061a9cbb21..705d12f3b3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2681,7 +2681,7 @@ void acpi_build(AcpiBuildTables *tables) /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets); + build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index c460bdd255..aa29d30d1f 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -364,6 +364,7 @@ void acpi_add_table(GArray *table_offsets, GArray *table_data); void acpi_build_tables_init(AcpiBuildTables *tables); void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre); void -build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets); +build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, + const char *oem_id, const char *oem_table_id); #endif From 88594e4fd1e916b778968b2bdd8d7375ca2fe8d8 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:12 +0100 Subject: [PATCH 40/45] acpi: add function to extract oem_id and oem_table_id from the user's SLIC The acpi_get_slic_oem() function stores pointers to these fields in the (first) SLIC table that the user passes in with the -acpitable switch. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Steven Newbury --- hw/acpi/core.c | 16 ++++++++++++++++ include/hw/acpi/acpi.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 397e6da9b6..edf3f960a7 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -350,6 +350,22 @@ uint8_t *acpi_table_next(uint8_t *current) } } +int acpi_get_slic_oem(AcpiSlicOem *oem) +{ + uint8_t *u; + + for (u = acpi_table_first(); u; u = acpi_table_next(u)) { + struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length)); + + if (memcmp(hdr->sig, "SLIC", 4) == 0) { + oem->id = hdr->oem_id; + oem->table_id = hdr->oem_table_id; + return 0; + } + } + return -1; +} + static void acpi_notify_wakeup(Notifier *notifier, void *data) { ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index b20bd55a67..2de30211f2 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -196,4 +196,11 @@ unsigned acpi_table_len(void *current); void acpi_table_add(const QemuOpts *opts, Error **errp); void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); +typedef struct AcpiSlicOem AcpiSlicOem; +struct AcpiSlicOem { + char *id; + char *table_id; +}; +int acpi_get_slic_oem(AcpiSlicOem *oem); + #endif /* !QEMU_HW_ACPI_H */ From ae12374951f07157f7a52c8d848b90f8eec722fb Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:13 +0100 Subject: [PATCH 41/45] pc: set the OEM fields in the RSDT and the FADT from the SLIC The Microsoft spec about the SLIC and MSDM ACPI tables at requires the OEM ID and OEM Table ID fields to be consistent between the SLIC and the RSDT/XSDT. That further affects the FADT, because a similar match between the FADT and the RSDT/XSDT is required by the ACPI spec in general. This patch wires up the previous three patches. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Paolo Bonzini (maintainer:X86) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Steven Newbury --- hw/i386/acpi-build.c | 13 +++++++++---- qemu-options.hx | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 705d12f3b3..4554eb88bc 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -336,7 +336,8 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm) /* FADT */ static void build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, - unsigned facs, unsigned dsdt) + unsigned facs, unsigned dsdt, + const char *oem_id, const char *oem_table_id) { AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); @@ -357,7 +358,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, fadt_setup(fadt, pm); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 1, NULL, NULL); + (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id); } static void @@ -2601,11 +2602,13 @@ void acpi_build(AcpiBuildTables *tables) uint8_t *u; size_t aml_len = 0; GArray *tables_blob = tables->table_data; + AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; acpi_get_cpu_info(&cpu); acpi_get_pm_info(&pm); acpi_get_misc_info(&misc); acpi_get_pci_info(&pci); + acpi_get_slic_oem(&slic_oem); table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -2635,7 +2638,8 @@ void acpi_build(AcpiBuildTables *tables) /* ACPI tables pointed to by RSDT */ fadt = tables_blob->len; acpi_add_table(table_offsets, tables_blob); - build_fadt(tables_blob, tables->linker, &pm, facs, dsdt); + build_fadt(tables_blob, tables->linker, &pm, facs, dsdt, + slic_oem.id, slic_oem.table_id); aml_len += tables_blob->len - fadt; acpi_add_table(table_offsets, tables_blob); @@ -2681,7 +2685,8 @@ void acpi_build(AcpiBuildTables *tables) /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); + build_rsdt(tables_blob, tables->linker, table_offsets, + slic_oem.id, slic_oem.table_id); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); diff --git a/qemu-options.hx b/qemu-options.hx index 733a1949e9..2f0465eeb1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1472,6 +1472,10 @@ ACPI headers (possible overridden by other options). For data=, only data portion of the table is used, all header information is specified in the command line. +If a SLIC table is supplied to QEMU, then the SLIC's oem_id and oem_table_id +fields will override the same in the RSDT and the FADT (a.k.a. FACP), in order +to ensure the field matches required by the Microsoft SLIC spec and the ACPI +spec. ETEXI DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, From adcb4ee660cf579f003e9d4afd61b608259091c6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 21 Jan 2016 12:37:51 +1100 Subject: [PATCH 42/45] dimm: Correct type of MemoryHotplugState->base The 'base' field of MemoryHotplugState is ram_addr_t, which indicates that it exists in the abstract address space of RAM regions. However, the actual usage of this field indicates that it is a concrete physical address (it's passed as an offset to memory_region_add_subgregion for example). So, correct its type to 'hwaddr'. Signed-off-by: David Gibson Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Acked-by: Eduardo Habkost --- include/hw/mem/pc-dimm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h index d83bf30ea9..218dfb0eda 100644 --- a/include/hw/mem/pc-dimm.h +++ b/include/hw/mem/pc-dimm.h @@ -77,7 +77,7 @@ typedef struct PCDIMMDeviceClass { * @mr: hotplug memory address space container */ typedef struct MemoryHotplugState { - ram_addr_t base; + hwaddr base; MemoryRegion mr; } MemoryHotplugState; From d66b969b0d9c8eefdcbff4b48535b0fe1501d139 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 14 Jan 2016 00:47:24 -0500 Subject: [PATCH 43/45] intel_iommu: large page support Current intel_iommu only supports 4K page which may not be sufficient to cover guest working set. This patch tries to enable 2M and 1G mapping for intel_iommu. This is also useful for future device IOTLB implementation to have a better hit rate. Major work is adding a page mask field on IOTLB entry to make it support large page. And also use the slpte level as key to do IOTLB lookup. MAMV was increased to 18 to support direct invalidation for 1G mapping. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 74 ++++++++++++++++++++++++---------- hw/i386/intel_iommu_internal.h | 6 ++- include/hw/i386/intel_iommu.h | 1 + 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index c25b1fd242..347718f938 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -153,14 +153,27 @@ static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value, return entry->domain_id == domain_id; } +/* The shift of an addr for a certain level of paging structure */ +static inline uint32_t vtd_slpt_level_shift(uint32_t level) +{ + return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS; +} + +static inline uint64_t vtd_slpt_level_page_mask(uint32_t level) +{ + return ~((1ULL << vtd_slpt_level_shift(level)) - 1); +} + static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value, gpointer user_data) { VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value; VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data; - uint64_t gfn = info->gfn & info->mask; + uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask; + uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K; return (entry->domain_id == info->domain_id) && - ((entry->gfn & info->mask) == gfn); + (((entry->gfn & info->mask) == gfn) || + (entry->gfn == gfn_tlb)); } /* Reset all the gen of VTDAddressSpace to zero and set the gen of @@ -194,24 +207,46 @@ static void vtd_reset_iotlb(IntelIOMMUState *s) g_hash_table_remove_all(s->iotlb); } +static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint8_t source_id, + uint32_t level) +{ + return gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT) | + ((uint64_t)(level) << VTD_IOTLB_LVL_SHIFT); +} + +static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level) +{ + return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K; +} + static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id, hwaddr addr) { + VTDIOTLBEntry *entry; uint64_t key; + int level; - key = (addr >> VTD_PAGE_SHIFT_4K) | - ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT); - return g_hash_table_lookup(s->iotlb, &key); + for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) { + key = vtd_get_iotlb_key(vtd_get_iotlb_gfn(addr, level), + source_id, level); + entry = g_hash_table_lookup(s->iotlb, &key); + if (entry) { + goto out; + } + } +out: + return entry; } static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, uint16_t domain_id, hwaddr addr, uint64_t slpte, - bool read_flags, bool write_flags) + bool read_flags, bool write_flags, + uint32_t level) { VTDIOTLBEntry *entry = g_malloc(sizeof(*entry)); uint64_t *key = g_malloc(sizeof(*key)); - uint64_t gfn = addr >> VTD_PAGE_SHIFT_4K; + uint64_t gfn = vtd_get_iotlb_gfn(addr, level); VTD_DPRINTF(CACHE, "update iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64 " slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr, slpte, @@ -226,7 +261,8 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, entry->slpte = slpte; entry->read_flags = read_flags; entry->write_flags = write_flags; - *key = gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT); + entry->mask = vtd_slpt_level_page_mask(level); + *key = vtd_get_iotlb_key(gfn, source_id, level); g_hash_table_replace(s->iotlb, key, entry); } @@ -501,12 +537,6 @@ static inline dma_addr_t vtd_get_slpt_base_from_context(VTDContextEntry *ce) return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR; } -/* The shift of an addr for a certain level of paging structure */ -static inline uint32_t vtd_slpt_level_shift(uint32_t level) -{ - return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS; -} - static inline uint64_t vtd_get_slpte_addr(uint64_t slpte) { return slpte & VTD_SL_PT_BASE_ADDR_MASK; @@ -762,7 +792,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, VTDContextEntry ce; uint8_t bus_num = pci_bus_num(bus); VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry; - uint64_t slpte; + uint64_t slpte, page_mask; uint32_t level; uint16_t source_id = vtd_make_source_id(bus_num, devfn); int ret_fr; @@ -802,6 +832,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, slpte = iotlb_entry->slpte; reads = iotlb_entry->read_flags; writes = iotlb_entry->write_flags; + page_mask = iotlb_entry->mask; goto out; } /* Try to fetch context-entry from cache first */ @@ -848,12 +879,13 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, return; } + page_mask = vtd_slpt_level_page_mask(level); vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte, - reads, writes); + reads, writes, level); out: - entry->iova = addr & VTD_PAGE_MASK_4K; - entry->translated_addr = vtd_get_slpte_addr(slpte) & VTD_PAGE_MASK_4K; - entry->addr_mask = ~VTD_PAGE_MASK_4K; + entry->iova = addr & page_mask; + entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask; + entry->addr_mask = ~page_mask; entry->perm = (writes ? 2 : 0) + (reads ? 1 : 0); } @@ -991,7 +1023,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, assert(am <= VTD_MAMV); info.domain_id = domain_id; - info.gfn = addr >> VTD_PAGE_SHIFT_4K; + info.addr = addr; info.mask = ~((1 << am) - 1); g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info); } @@ -1917,7 +1949,7 @@ static void vtd_init(IntelIOMMUState *s) s->iq_last_desc_type = VTD_INV_DESC_NONE; s->next_frcd_reg = 0; s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW | - VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI; + VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS; s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; vtd_reset_context_cache(s); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index ba288ab1d9..e5f514c6e3 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -113,6 +113,7 @@ /* The shift of source_id in the key of IOTLB hash table */ #define VTD_IOTLB_SID_SHIFT 36 +#define VTD_IOTLB_LVL_SHIFT 44 #define VTD_IOTLB_MAX_SIZE 1024 /* Max size of the hash table */ /* IOTLB_REG */ @@ -185,9 +186,10 @@ #define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL) #define VTD_MGAW 39 /* Maximum Guest Address Width */ #define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16) -#define VTD_MAMV 9ULL +#define VTD_MAMV 18ULL #define VTD_CAP_MAMV (VTD_MAMV << 48) #define VTD_CAP_PSI (1ULL << 39) +#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35)) /* Supported Adjusted Guest Address Widths */ #define VTD_CAP_SAGAW_SHIFT 8 @@ -320,7 +322,7 @@ typedef struct VTDInvDesc VTDInvDesc; /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { uint16_t domain_id; - uint64_t gfn; + uint64_t addr; uint8_t mask; }; typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb785c..b024ffa720 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -83,6 +83,7 @@ struct VTDIOTLBEntry { uint64_t gfn; uint16_t domain_id; uint64_t slpte; + uint64_t mask; bool read_flags; bool write_flags; }; From 428c3ece97179557f2753071fb0ca97a03437267 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 13 Jan 2016 14:59:09 +0000 Subject: [PATCH 44/45] fix MSI injection on Xen On Xen MSIs can be remapped into pirqs, which are a type of event channels. It's mostly for the benefit of PCI passthrough devices, to avoid the overhead of interacting with the emulated lapic. However remapping interrupts and MSIs is also supported for emulated devices, such as the e1000 and virtio-net. When an interrupt or an MSI is remapped into a pirq, masking and unmasking is done by masking and unmasking the event channel. The masking bit on the PCI config space or MSI-X table should be ignored, but it isn't at the moment. As a consequence emulated devices which use MSI or MSI-X, such as virtio-net, don't work properly (the guest doesn't receive any notifications). The mechanism was working properly when xen_apic was introduced, but I haven't narrowed down which commit in particular is causing the regression. Fix the issue by ignoring the masking bit for MSI and MSI-X which have been remapped into pirqs. Signed-off-by: Stefano Stabellini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/msi.c | 9 ++++++++- hw/pci/msix.c | 12 ++++++++++-- hw/xen/xen_pt_msi.c | 4 +--- include/hw/xen/xen.h | 1 + xen-hvm-stub.c | 5 +++++ xen-hvm.c | 9 +++++++++ 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/hw/pci/msi.c b/hw/pci/msi.c index 8efa23d376..85f21b8c4b 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/pci/msi.h" +#include "hw/xen/xen.h" #include "qemu/range.h" /* PCI_MSI_ADDRESS_LO */ @@ -254,13 +255,19 @@ void msi_reset(PCIDevice *dev) static bool msi_is_masked(const PCIDevice *dev, unsigned int vector) { uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); - uint32_t mask; + uint32_t mask, data; + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; assert(vector < PCI_MSI_VECTORS_MAX); if (!(flags & PCI_MSI_FLAGS_MASKBIT)) { return false; } + data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); + if (xen_is_pirq_msi(data)) { + return false; + } + mask = pci_get_long(dev->config + msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT)); return mask & (1U << vector); diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 4fea7edc89..eb4ef113d1 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -19,6 +19,7 @@ #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/pci/pci.h" +#include "hw/xen/xen.h" #include "qemu/range.h" #define MSIX_CAP_LENGTH 12 @@ -78,8 +79,15 @@ static void msix_clr_pending(PCIDevice *dev, int vector) static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask) { - unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; - return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; + unsigned offset = vector * PCI_MSIX_ENTRY_SIZE; + uint32_t *data = (uint32_t *)&dev->msix_table[offset + PCI_MSIX_ENTRY_DATA]; + /* MSIs on Xen can be remapped into pirqs. In those cases, masking + * and unmasking go through the PV evtchn path. */ + if (xen_is_pirq_msi(*data)) { + return false; + } + return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] & + PCI_MSIX_ENTRY_CTRL_MASKBIT; } bool msix_is_masked(PCIDevice *dev, unsigned int vector) diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index 5624685b20..9a16f2bff1 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -115,9 +115,7 @@ static int msi_msix_setup(XenPCIPassthroughState *s, assert((!is_msix && msix_entry == 0) || is_msix); - if (gvec == 0) { - /* if gvec is 0, the guest is asking for a particular pirq that - * is passed as dest_id */ + if (xen_is_pirq_msi(data)) { *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr); if (!*ppirq) { /* this probably identifies an misconfiguration of the guest, diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 1b81b4be9a..c57735419c 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -33,6 +33,7 @@ int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); void xen_hvm_inject_msi(uint64_t addr, uint32_t data); +int xen_is_pirq_msi(uint32_t msi_data); qemu_irq *xen_interrupt_controller_init(void); diff --git a/xen-hvm-stub.c b/xen-hvm-stub.c index a6cb5d358f..c5003251cb 100644 --- a/xen-hvm-stub.c +++ b/xen-hvm-stub.c @@ -31,6 +31,11 @@ void xen_hvm_inject_msi(uint64_t addr, uint32_t data) { } +int xen_is_pirq_msi(uint32_t msi_data) +{ + return 0; +} + void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr, Error **errp) { diff --git a/xen-hvm.c b/xen-hvm.c index 1c9fb12955..6861c51ef9 100644 --- a/xen-hvm.c +++ b/xen-hvm.c @@ -13,6 +13,7 @@ #include "hw/pci/pci.h" #include "hw/i386/pc.h" +#include "hw/i386/apic-msidef.h" #include "hw/xen/xen_common.h" #include "hw/xen/xen_backend.h" #include "qmp-commands.h" @@ -158,6 +159,14 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) } } +int xen_is_pirq_msi(uint32_t msi_data) +{ + /* If vector is 0, the msi is remapped into a pirq, passed as + * dest_id. + */ + return ((msi_data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT) == 0; +} + void xen_hvm_inject_msi(uint64_t addr, uint32_t data) { xen_xc_hvm_inject_msi(xen_xc, xen_domid, addr, data); From a407644079c8639002e7ea635d851953b10a38c3 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 13 Jan 2016 20:26:25 +0100 Subject: [PATCH 45/45] net: set endianness on all backend devices commit 5be7d9f1b1452613b95c6ba70b8d7ad3d0797991 vhost-net: tell tap backend about the vnet endianness makes vhost net to set the endianness of the device, but only for the first device. In case of multiqueue, we have multiple devices... This patch sets the endianness for all the devices of the interface. Signed-off-by: Laurent Vivier Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Greg Kurz Reviewed-by: Cornelia Huck Reviewed-by: Jason Wang --- hw/net/vhost_net.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 0bd5131fdb..3940a04b65 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -298,21 +298,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); VirtioBusState *vbus = VIRTIO_BUS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); - int r, e, i; + int r, e, i, j; if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); - r = -ENOSYS; - goto err; + return -ENOSYS; } - r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true); - if (r < 0) { - goto err; - } - - for (i = 0; i < total_queues; i++) { - vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2); + for (j = 0; j < total_queues; j++) { + r = vhost_net_set_vnet_endian(dev, ncs[j].peer, true); + if (r < 0) { + goto err_endian; + } + vhost_net_set_vq_index(get_vhost_net(ncs[j].peer), j * 2); } r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true); @@ -341,8 +339,9 @@ err_start: fflush(stderr); } err_endian: - vhost_net_set_vnet_endian(dev, ncs[0].peer, false); -err: + while (--j >= 0) { + vhost_net_set_vnet_endian(dev, ncs[j].peer, false); + } return r; }