From 13cc2c3e867605122351c68f34af838bc75d8692 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 27 Feb 2014 02:05:05 +0100 Subject: [PATCH 01/10] serial-pci: Set prog interface field of pci config to 16550 compatible Signed-off-by: BALATON Zoltan Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Gerd Hoffmann --- hw/char/serial-pci.c | 7 +++++++ include/hw/i386/pc.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 991c99fa6e..acccc9cabd 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -34,6 +34,7 @@ typedef struct PCISerialState { PCIDevice dev; SerialState state; + uint8_t prog_if; } PCISerialState; typedef struct PCIMultiSerialState { @@ -44,6 +45,7 @@ typedef struct PCIMultiSerialState { SerialState state[PCI_SERIAL_MAX_PORTS]; uint32_t level[PCI_SERIAL_MAX_PORTS]; qemu_irq *irqs; + uint8_t prog_if; } PCIMultiSerialState; static int serial_pci_init(PCIDevice *dev) @@ -60,6 +62,7 @@ static int serial_pci_init(PCIDevice *dev) return -1; } + pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; s->irq = pci_allocate_irq(&pci->dev); @@ -101,6 +104,7 @@ static int multi_serial_pci_init(PCIDevice *dev) assert(pci->ports > 0); assert(pci->ports <= PCI_SERIAL_MAX_PORTS); + pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * pci->ports); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); @@ -177,12 +181,14 @@ static const VMStateDescription vmstate_pci_multi_serial = { static Property serial_pci_properties[] = { DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), + DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), DEFINE_PROP_END_OF_LIST(), }; static Property multi_2x_serial_pci_properties[] = { DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), DEFINE_PROP_END_OF_LIST(), }; @@ -191,6 +197,7 @@ static Property multi_4x_serial_pci_properties[] = { DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), + DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 32a76876c7..552fbd8243 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -271,6 +271,21 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .driver = "apic",\ .property = "version",\ .value = stringify(0x11),\ + },\ + {\ + .driver = "pci-serial",\ + .property = "prog_if",\ + .value = stringify(0),\ + },\ + {\ + .driver = "pci-serial-2x",\ + .property = "prof_if",\ + .value = stringify(0),\ + },\ + {\ + .driver = "pci-serial-4x",\ + .property = "prog_if",\ + .value = stringify(0),\ } #define PC_COMPAT_1_7 \ From fb5be2e833669dd95be1950ea7b1da4cf7f9556c Mon Sep 17 00:00:00 2001 From: "Gabriel L. Somlo" Date: Mon, 19 May 2014 10:09:53 -0400 Subject: [PATCH 02/10] SMBIOS: Fix endian-ness when populating multi-byte fields When i386 guests are emulated on big endian hosts, make sure multi-byte fields are populated safely via cpu_to_le*(). Signed-off-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/smbios.c | 92 +++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index 76607181c3..aeb94bc671 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -444,7 +444,7 @@ static bool smbios_skip_table(uint8_t type, bool required_table) \ t->header.type = tbl_type; \ t->header.length = sizeof(*t); \ - t->header.handle = tbl_handle; \ + t->header.handle = cpu_to_le16(tbl_handle); \ } while (0) #define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ @@ -491,7 +491,7 @@ static void smbios_build_type_0_table(void) SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor); SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version); - t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */ + t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */ SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date); @@ -551,7 +551,7 @@ static void smbios_build_type_2_table(void) SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset); t->feature_flags = 0x01; /* Motherboard */ SMBIOS_TABLE_SET_STR(2, location_str, type2.location); - t->chassis_handle = 0x300; /* Type 3 (System enclosure) */ + t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */ t->board_type = 0x0A; /* Motherboard */ t->contained_element_count = 0; @@ -571,7 +571,7 @@ static void smbios_build_type_3_table(void) t->power_supply_state = 0x03; /* Safe */ t->thermal_state = 0x03; /* Safe */ t->security_status = 0x02; /* Unknown */ - t->oem_defined = 0; + t->oem_defined = cpu_to_le32(0); t->height = 0; t->number_of_power_cords = 0; t->contained_element_count = 0; @@ -589,26 +589,27 @@ static void smbios_build_type_4_table(unsigned instance) snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); t->processor_type = 0x03; /* CPU */ + t->processor_family = 0x01; /* Other */ SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); - t->processor_id[0] = smbios_cpuid_version; - t->processor_id[1] = smbios_cpuid_features; + t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); + t->processor_id[1] = cpu_to_le32(smbios_cpuid_features); SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version); t->voltage = 0; - t->external_clock = 0; /* Unknown */ - t->max_speed = 0; /* Unknown */ - t->current_speed = 0; /* Unknown */ + t->external_clock = cpu_to_le16(0); /* Unknown */ + t->max_speed = cpu_to_le16(0); /* Unknown */ + t->current_speed = cpu_to_le16(0); /* Unknown */ t->status = 0x41; /* Socket populated, CPU enabled */ t->processor_upgrade = 0x01; /* Other */ - t->l1_cache_handle = 0xFFFF; /* N/A */ - t->l2_cache_handle = 0xFFFF; /* N/A */ - t->l3_cache_handle = 0xFFFF; /* N/A */ + t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ + t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ + t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial); SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); t->core_count = t->core_enabled = smp_cores; t->thread_count = smp_threads; - t->processor_characteristics = 0x02; /* Unknown */ - t->processor_family = t->processor_family2 = 0x01; /* Other */ + t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ + t->processor_family2 = cpu_to_le16(0x01); /* Other */ SMBIOS_BUILD_TABLE_POST; smbios_type4_count++; @@ -631,14 +632,14 @@ static void smbios_build_type_16_table(unsigned dimm_cnt) t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */ size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB; if (size_kb < MAX_T16_STD_SZ) { - t->maximum_capacity = size_kb; - t->extended_maximum_capacity = 0; + t->maximum_capacity = cpu_to_le32(size_kb); + t->extended_maximum_capacity = cpu_to_le64(0); } else { - t->maximum_capacity = MAX_T16_STD_SZ; - t->extended_maximum_capacity = ram_size; + t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ); + t->extended_maximum_capacity = cpu_to_le64(ram_size); } - t->memory_error_information_handle = 0xFFFE; /* Not provided */ - t->number_of_memory_devices = dimm_cnt; + t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ + t->number_of_memory_devices = cpu_to_le16(dimm_cnt); SMBIOS_BUILD_TABLE_POST; } @@ -653,18 +654,18 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ - t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */ - t->memory_error_information_handle = 0xFFFE; /* Not provided */ - t->total_width = 0xFFFF; /* Unknown */ - t->data_width = 0xFFFF; /* Unknown */ + t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ + t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ + t->total_width = cpu_to_le16(0xFFFF); /* Unknown */ + t->data_width = cpu_to_le16(0xFFFF); /* Unknown */ size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB; if (size_mb < MAX_T17_STD_SZ) { - t->size = size_mb; - t->extended_size = 0; + t->size = cpu_to_le16(size_mb); + t->extended_size = cpu_to_le32(0); } else { assert(size_mb < MAX_T17_EXT_SZ); - t->size = MAX_T17_STD_SZ; - t->extended_size = size_mb; + t->size = cpu_to_le16(MAX_T17_STD_SZ); + t->extended_size = cpu_to_le32(size_mb); } t->form_factor = 0x09; /* DIMM */ t->device_set = 0; /* Not in a set */ @@ -672,17 +673,17 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str); SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank); t->memory_type = 0x07; /* RAM */ - t->type_detail = 0x02; /* Other */ - t->speed = 0; /* Unknown */ + t->type_detail = cpu_to_le16(0x02); /* Other */ + t->speed = cpu_to_le16(0); /* Unknown */ SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer); SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial); SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset); SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part); t->attributes = 0; /* Unknown */ - t->configured_clock_speed = 0; /* Unknown */ - t->minimum_voltage = 0; /* Unknown */ - t->maximum_voltage = 0; /* Unknown */ - t->configured_voltage = 0; /* Unknown */ + t->configured_clock_speed = cpu_to_le32(0); /* Unknown */ + t->minimum_voltage = cpu_to_le32(0); /* Unknown */ + t->maximum_voltage = cpu_to_le32(0); /* Unknown */ + t->configured_voltage = cpu_to_le32(0); /* Unknown */ SMBIOS_BUILD_TABLE_POST; } @@ -699,15 +700,16 @@ static void smbios_build_type_19_table(unsigned instance, start_kb = start / ONE_KB; end_kb = end / ONE_KB; if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) { - t->starting_address = start_kb; - t->ending_address = end_kb; - t->extended_starting_address = t->extended_ending_address = 0; + t->starting_address = cpu_to_le32(start_kb); + t->ending_address = cpu_to_le32(end_kb); + t->extended_starting_address = + t->extended_ending_address = cpu_to_le64(0); } else { - t->starting_address = t->ending_address = UINT32_MAX; - t->extended_starting_address = start; - t->extended_ending_address = end; + t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX); + t->extended_starting_address = cpu_to_le64(start); + t->extended_ending_address = cpu_to_le64(end); } - t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */ + t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ t->partition_width = 1; /* One device per row */ SMBIOS_BUILD_TABLE_POST; @@ -794,14 +796,14 @@ static void smbios_entry_point_setup(void) ep.smbios_bcd_revision = 0x28; /* set during table construction, but BIOS may override: */ - ep.structure_table_length = smbios_tables_len; - ep.max_structure_size = smbios_table_max; - ep.number_of_structures = smbios_table_cnt; + ep.structure_table_length = cpu_to_le16(smbios_tables_len); + ep.max_structure_size = cpu_to_le16(smbios_table_max); + ep.number_of_structures = cpu_to_le16(smbios_table_cnt); /* BIOS must recalculate: */ ep.checksum = 0; ep.intermediate_checksum = 0; - ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */ + ep.structure_table_address = cpu_to_le32(0); } void smbios_get_tables(uint8_t **tables, size_t *tables_len, From 84351843eba330022e245a742899cf71fc817ec5 Mon Sep 17 00:00:00 2001 From: "Gabriel L. Somlo" Date: Mon, 19 May 2014 10:09:54 -0400 Subject: [PATCH 03/10] SMBIOS: Update Type 0 struct generator for machines >= 2.1 Update how type 0 (bios info) structures are generated, as follows: - convert bios_characteristics field to uin64_t (instead of uint8_t[8]), as described in the current smbios spec (v2.8) - enable "virtual machine" bit in bios_characteristics_extension_bits - add command line option to enable "uefi supported" bit in bios_characteristics_extension_bits These updates should make this optional structure more useful when used with edk2/ovmf. Only pc machines >= 2.1 are affected, and only when a type 0 structure is explicitly specified on the command line. Signed-off-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/smbios.c | 18 +++++++++++------- include/hw/i386/smbios.h | 2 +- qemu-options.hx | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index aeb94bc671..17938215f6 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -67,7 +67,7 @@ static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1); static struct { const char *vendor, *version, *date; - bool have_major_minor; + bool have_major_minor, uefi; uint8_t major, minor; } type0; @@ -134,6 +134,10 @@ static const QemuOptDesc qemu_smbios_type0_opts[] = { .name = "release", .type = QEMU_OPT_STRING, .help = "revision number", + },{ + .name = "uefi", + .type = QEMU_OPT_BOOL, + .help = "uefi support", }, { /* end of list */ } }; @@ -497,13 +501,12 @@ static void smbios_build_type_0_table(void) t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */ - /* BIOS characteristics not supported */ - memset(t->bios_characteristics, 0, 8); - t->bios_characteristics[0] = 0x08; - - /* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */ + t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */ t->bios_characteristics_extension_bytes[0] = 0; - t->bios_characteristics_extension_bytes[1] = 4; + t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */ + if (type0.uefi) { + t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */ + } if (type0.have_major_minor) { t->system_bios_major_release = type0.major; @@ -979,6 +982,7 @@ void smbios_entry_add(QemuOpts *opts) save_opt(&type0.vendor, opts, "vendor"); save_opt(&type0.version, opts, "version"); save_opt(&type0.date, opts, "date"); + type0.uefi = qemu_opt_get_bool(opts, "uefi", false); val = qemu_opt_get(opts, "release"); if (val) { diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index 6d854b7f1e..5583f60405 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -64,7 +64,7 @@ struct smbios_type_0 { uint16_t bios_starting_address_segment; uint8_t bios_release_date_str; uint8_t bios_rom_size; - uint8_t bios_characteristics[8]; + uint64_t bios_characteristics; uint8_t bios_characteristics_extension_bytes[2]; uint8_t system_bios_major_release; uint8_t system_bios_minor_release; diff --git a/qemu-options.hx b/qemu-options.hx index 781af14bf5..15779e723e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1335,7 +1335,7 @@ ETEXI DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, "-smbios file=binary\n" " load SMBIOS entry from binary file\n" - "-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d]\n" + "-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d][,uefi=on|off]\n" " specify SMBIOS type 0 fields\n" "-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]\n" " [,uuid=uuid][,sku=str][,family=str]\n" @@ -1345,7 +1345,7 @@ STEXI @findex -smbios Load SMBIOS entry from binary file. -@item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}] +@item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}][,uefi=on|off] Specify SMBIOS type 0 fields @item -smbios type=1[,manufacturer=@var{str}][,product=@var{str}] [,version=@var{str}][,serial=@var{str}][,uuid=@var{uuid}][,sku=@var{str}] [,family=@var{str}] From 0d73394ad93aa12755316b3a90b3193aeeb95f90 Mon Sep 17 00:00:00 2001 From: "Gabriel L. Somlo" Date: Mon, 19 May 2014 10:09:55 -0400 Subject: [PATCH 04/10] SMBIOS: Fix type 17 field sizes Fields for configured_clock_speed and various voltage values introduced in spec v2.7+ should be "word", i.e. 16 bits. Reported-by: Laszlo Ersek Signed-off-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/smbios.c | 8 ++++---- include/hw/i386/smbios.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index 17938215f6..b3bedde8b9 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -683,10 +683,10 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset); SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part); t->attributes = 0; /* Unknown */ - t->configured_clock_speed = cpu_to_le32(0); /* Unknown */ - t->minimum_voltage = cpu_to_le32(0); /* Unknown */ - t->maximum_voltage = cpu_to_le32(0); /* Unknown */ - t->configured_voltage = cpu_to_le32(0); /* Unknown */ + t->configured_clock_speed = cpu_to_le16(0); /* Unknown */ + t->minimum_voltage = cpu_to_le16(0); /* Unknown */ + t->maximum_voltage = cpu_to_le16(0); /* Unknown */ + t->configured_voltage = cpu_to_le16(0); /* Unknown */ SMBIOS_BUILD_TABLE_POST; } diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index 5583f60405..a3f4d88bf0 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -182,10 +182,10 @@ struct smbios_type_17 { uint8_t part_number_str; uint8_t attributes; uint32_t extended_size; - uint32_t configured_clock_speed; - uint32_t minimum_voltage; - uint32_t maximum_voltage; - uint32_t configured_voltage; + uint16_t configured_clock_speed; + uint16_t minimum_voltage; + uint16_t maximum_voltage; + uint16_t configured_voltage; } QEMU_PACKED; /* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */ From 7c8b7248261bfa5e54eff1715b699caa8b3f1d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 24 Apr 2014 17:26:51 +0200 Subject: [PATCH 05/10] pcie_host: Turn pcie_host_init() into an instance_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This assures the trivial field initialization is applied for any derived type - currently only Q35PCIHost. Signed-off-by: Andreas Färber Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-host/q35.c | 4 ---- hw/pci/pcie_host.c | 7 ++++--- include/hw/pci/pcie_host.h | 1 - 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 8b8cc4e294..aa48b1c82f 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -47,10 +47,6 @@ static void q35_host_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem); sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, 4); - if (pcie_host_init(PCIE_HOST_BRIDGE(s)) < 0) { - error_setg(errp, "failed to initialize pcie host"); - return; - } pci->bus = pci_bus_new(DEVICE(s), "pcie.0", s->mch.pci_address_space, s->mch.address_space_io, 0, TYPE_PCIE_BUS); diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index c6e1b573e1..7c88a1d091 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -83,11 +83,11 @@ static const MemoryRegionOps pcie_mmcfg_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -int pcie_host_init(PCIExpressHost *e) +static void pcie_host_init(Object *obj) { - e->base_addr = PCIE_BASE_ADDR_UNMAPPED; + PCIExpressHost *e = PCIE_HOST_BRIDGE(obj); - return 0; + e->base_addr = PCIE_BASE_ADDR_UNMAPPED; } void pcie_host_mmcfg_unmap(PCIExpressHost *e) @@ -128,6 +128,7 @@ static const TypeInfo pcie_host_type_info = { .parent = TYPE_PCI_HOST_BRIDGE, .abstract = true, .instance_size = sizeof(PCIExpressHost), + .instance_init = pcie_host_init, }; static void pcie_host_register_types(void) diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index acca45ed58..ff44ef6fca 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -49,7 +49,6 @@ struct PCIExpressHost { MemoryRegion mmio; }; -int pcie_host_init(PCIExpressHost *e); void pcie_host_mmcfg_unmap(PCIExpressHost *e); void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); void pcie_host_mmcfg_update(PCIExpressHost *e, From 38dbd48b247ebe05bdc6ef52ccdc60cc21274877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Tomko?= Date: Wed, 21 May 2014 11:03:47 +0200 Subject: [PATCH 06/10] virtio-balloon: return empty data when no stats are available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the guest hasn't updated the stats yet, instead of returning an error, return '-1' for the stats and '0' as 'last-update'. This lets applications ignore this without parsing the error message. Related libvirt patch and discussion: https://www.redhat.com/archives/libvir-list/2014-May/msg00460.html Tested against current upstream libvirt - stat reporting works and it no longer logs errors when the stats are queried on domain startup. (Note: libvirt doesn't use the last-update field for anything yet) Signed-off-by: Ján Tomko Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Eric Blake --- docs/virtio-balloon-stats.txt | 5 +++-- hw/virtio/virtio-balloon.c | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/virtio-balloon-stats.txt b/docs/virtio-balloon-stats.txt index f74612f468..edff5f22a8 100644 --- a/docs/virtio-balloon-stats.txt +++ b/docs/virtio-balloon-stats.txt @@ -35,7 +35,8 @@ which will return a dictionary containing: o A key named last-update, which contains the last stats update timestamp in seconds. Since this timestamp is generated by the host, - a buggy guest can't influence its value + a buggy guest can't influence its value. The value is 0 if the guest + has not updated the stats (yet). It's also important to note the following: @@ -49,7 +50,7 @@ It's also important to note the following: - Polling can be enabled even if the guest doesn't have stats support or the balloon driver wasn't loaded in the guest. If this is the case - and stats are queried, an error will be returned + and stats are queried, last-update will be 0. - The polling timer is only re-armed when the guest responds to the statistics request. This means that if a (buggy) guest doesn't ever diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index bf2b588b24..22cd52edee 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -112,11 +112,6 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v, VirtIOBalloon *s = opaque; int i; - if (!s->stats_last_update) { - error_setg(errp, "guest hasn't updated any stats yet"); - return; - } - visit_start_struct(v, NULL, "guest-stats", name, 0, &err); if (err) { goto out; @@ -378,6 +373,8 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); + reset_stats(s); + register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); From 501f28ca9db08e84819b26314525b6369e7704dd Mon Sep 17 00:00:00 2001 From: "Gabriel L. Somlo" Date: Tue, 27 May 2014 15:03:14 -0400 Subject: [PATCH 07/10] tests: rename acpi-test to bios-tables-test The test harness for acpi (generating a boot disk, starting qemu, waiting for the BIOS to finish booting before examining guest memory, etc.) is perfectly suited for testing other bios tables beside acpi, such as e.g., smbios. This patch renames acpi-test to bios-tables-test to reflect that, and in preparation for adding smbios tests. Signed-off-by: Gabriel Somlo Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/Makefile | 4 ++-- tests/{acpi-test.c => bios-tables-test.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/{acpi-test.c => bios-tables-test.c} (100%) diff --git a/tests/Makefile b/tests/Makefile index 9f7ca61ae3..ba93e8a1d4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -131,7 +131,7 @@ check-qtest-i386-y += tests/ide-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) -check-qtest-i386-y += tests/acpi-test$(EXESUF) +check-qtest-i386-y += tests/bios-tables-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) @@ -286,7 +286,7 @@ tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) -tests/acpi-test$(EXESUF): tests/acpi-test.o $(libqos-obj-y) +tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) diff --git a/tests/acpi-test.c b/tests/bios-tables-test.c similarity index 100% rename from tests/acpi-test.c rename to tests/bios-tables-test.c From eb386aaccc4a728f5429de06ef7e6c698603d173 Mon Sep 17 00:00:00 2001 From: "Gabriel L. Somlo" Date: Tue, 27 May 2014 15:03:15 -0400 Subject: [PATCH 08/10] tests: add smbios testing Add tests to find and verify the smbios entry point structure, and to walk and perform checks on the actual smbios tables. Suggested-by: Michael S. Tsirkin Signed-off-by: Gabriel Somlo Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 76fbccfa4b..62771f7608 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -18,6 +18,8 @@ #include "libqtest.h" #include "qemu/compiler.h" #include "hw/i386/acpi-defs.h" +#include "hw/i386/smbios.h" +#include "qemu/bitmap.h" #define MACHINE_PC "pc" #define MACHINE_Q35 "q35" @@ -46,6 +48,8 @@ typedef struct { uint32_t *rsdt_tables_addr; int rsdt_tables_nr; GArray *tables; + uint32_t smbios_ep_addr; + struct smbios_entry_point smbios_ep_table; } test_data; #define LOW(x) ((x) & 0xff) @@ -581,6 +585,124 @@ static void test_acpi_asl(test_data *data) free_test_data(&exp_data); } +static void test_smbios_ep_address(test_data *data) +{ + uint32_t off; + + /* find smbios entry point structure */ + for (off = 0xf0000; off < 0x100000; off += 0x10) { + uint8_t sig[] = "_SM_"; + int i; + + for (i = 0; i < sizeof sig - 1; ++i) { + sig[i] = readb(off + i); + } + + if (!memcmp(sig, "_SM_", sizeof sig)) { + break; + } + } + + g_assert_cmphex(off, <, 0x100000); + data->smbios_ep_addr = off; +} + +static void test_smbios_ep_table(test_data *data) +{ + struct smbios_entry_point *ep_table = &data->smbios_ep_table; + uint32_t addr = data->smbios_ep_addr; + + ACPI_READ_ARRAY(ep_table->anchor_string, addr); + g_assert(!memcmp(ep_table->anchor_string, "_SM_", 4)); + ACPI_READ_FIELD(ep_table->checksum, addr); + ACPI_READ_FIELD(ep_table->length, addr); + ACPI_READ_FIELD(ep_table->smbios_major_version, addr); + ACPI_READ_FIELD(ep_table->smbios_minor_version, addr); + ACPI_READ_FIELD(ep_table->max_structure_size, addr); + ACPI_READ_FIELD(ep_table->entry_point_revision, addr); + ACPI_READ_ARRAY(ep_table->formatted_area, addr); + ACPI_READ_ARRAY(ep_table->intermediate_anchor_string, addr); + g_assert(!memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)); + ACPI_READ_FIELD(ep_table->intermediate_checksum, addr); + ACPI_READ_FIELD(ep_table->structure_table_length, addr); + g_assert_cmpuint(ep_table->structure_table_length, >, 0); + ACPI_READ_FIELD(ep_table->structure_table_address, addr); + ACPI_READ_FIELD(ep_table->number_of_structures, addr); + g_assert_cmpuint(ep_table->number_of_structures, >, 0); + ACPI_READ_FIELD(ep_table->smbios_bcd_revision, addr); + g_assert(!acpi_checksum((uint8_t *)ep_table, sizeof *ep_table)); + g_assert(!acpi_checksum((uint8_t *)ep_table + 0x10, + sizeof *ep_table - 0x10)); +} + +static inline bool smbios_single_instance(uint8_t type) +{ + switch (type) { + case 0: + case 1: + case 2: + case 3: + case 16: + case 32: + case 127: + return true; + default: + return false; + } +} + +static void test_smbios_structs(test_data *data) +{ + DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 }; + struct smbios_entry_point *ep_table = &data->smbios_ep_table; + uint32_t addr = ep_table->structure_table_address; + int i, len, max_len = 0; + uint8_t type, prv, crt; + uint8_t required_struct_types[] = {0, 1, 3, 4, 16, 17, 19, 32, 127}; + + /* walk the smbios tables */ + for (i = 0; i < ep_table->number_of_structures; i++) { + + /* grab type and formatted area length from struct header */ + type = readb(addr); + g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE); + len = readb(addr + 1); + + /* single-instance structs must not have been encountered before */ + if (smbios_single_instance(type)) { + g_assert(!test_bit(type, struct_bitmap)); + } + set_bit(type, struct_bitmap); + + /* seek to end of unformatted string area of this struct ("\0\0") */ + prv = crt = 1; + while (prv || crt) { + prv = crt; + crt = readb(addr + len); + len++; + } + + /* keep track of max. struct size */ + if (max_len < len) { + max_len = len; + g_assert_cmpuint(max_len, <=, ep_table->max_structure_size); + } + + /* start of next structure */ + addr += len; + } + + /* total table length and max struct size must match entry point values */ + g_assert_cmpuint(ep_table->structure_table_length, ==, + addr - ep_table->structure_table_address); + g_assert_cmpuint(ep_table->max_structure_size, ==, max_len); + + /* required struct types must all be present */ + for (i = 0; i < ARRAY_SIZE(required_struct_types); i++) { + g_assert(test_bit(required_struct_types[i], struct_bitmap)); + } +} + static void test_acpi_one(const char *params, test_data *data) { char *args; @@ -633,6 +755,10 @@ static void test_acpi_one(const char *params, test_data *data) } } + test_smbios_ep_address(data); + test_smbios_ep_table(data); + test_smbios_structs(data); + qtest_quit(global_qtest); g_free(args); } From 9f9260a3be3b7fbd0006a58773abdb164bf9f220 Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Mon, 5 May 2014 14:03:06 -0400 Subject: [PATCH 09/10] qdev: Display warning about unused -global This can help a user understand why -global was ignored. For example: with "-vga cirrus"; "-global vga.vgamem_mb=16" is just ignored when "-global cirrus-vga.vgamem_mb=16" is not. This is currently clear when the wrong property is provided: out/x86_64-softmmu/qemu-system-x86_64 -global cirrus-vga.vram_size_mb=16 -monitor pty -vga cirrus char device redirected to /dev/pts/20 (label compat_monitor0) qemu-system-x86_64: Property '.vram_size_mb' not found Aborted (core dumped) vs out/x86_64-softmmu/qemu-system-x86_64 -global vga.vram_size_mb=16 -monitor pty -vga cirrus char device redirected to /dev/pts/20 (label compat_monitor0) VNC server running on `::1:5900' ^Cqemu: terminating on signal 2 Signed-off-by: Don Slutz Acked-by: Michael S. Tsirkin --- hw/core/qdev-properties-system.c | 16 ++++++++++++++++ hw/core/qdev-properties.c | 18 ++++++++++++++++++ include/hw/qdev-core.h | 8 ++++++++ include/hw/qdev-properties.h | 1 + vl.c | 2 ++ 5 files changed, 45 insertions(+) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 404cf1843d..de433b2e38 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -439,11 +439,27 @@ PropertyInfo qdev_prop_iothread = { static int qdev_add_one_global(QemuOpts *opts, void *opaque) { GlobalProperty *g; + ObjectClass *oc; g = g_malloc0(sizeof(*g)); g->driver = qemu_opt_get(opts, "driver"); g->property = qemu_opt_get(opts, "property"); g->value = qemu_opt_get(opts, "value"); + oc = object_class_by_name(g->driver); + if (oc) { + DeviceClass *dc = DEVICE_CLASS(oc); + + if (dc->hotpluggable) { + /* If hotpluggable then skip not_used checking. */ + g->not_used = false; + } else { + /* Maybe a typo. */ + g->not_used = true; + } + } else { + /* Maybe a typo. */ + g->not_used = true; + } qdev_prop_register_global(g); return 0; } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index d8cb5408c3..3d12560f43 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -955,6 +955,23 @@ void qdev_prop_register_global_list(GlobalProperty *props) } } +int qdev_prop_check_global(void) +{ + GlobalProperty *prop; + int ret = 0; + + QTAILQ_FOREACH(prop, &global_props, next) { + if (!prop->not_used) { + continue; + } + ret = 1; + error_report("Warning: \"-global %s.%s=%s\" not used", + prop->driver, prop->property, prop->value); + + } + return ret; +} + void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, Error **errp) { @@ -966,6 +983,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, if (strcmp(typename, prop->driver) != 0) { continue; } + prop->not_used = false; object_property_parse(OBJECT(dev), prop->value, prop->property, &err); if (err != NULL) { error_propagate(errp, err); diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index dbe473c344..bbed82951f 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -231,10 +231,18 @@ struct PropertyInfo { ObjectPropertyRelease *release; }; +/** + * GlobalProperty: + * @not_used: Track use of a global property. Defaults to false in all C99 + * struct initializations. + * + * This prevents reports of .compat_props when they are not used. + */ typedef struct GlobalProperty { const char *driver; const char *property; const char *value; + bool not_used; QTAILQ_ENTRY(GlobalProperty) next; } GlobalProperty; diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index c46e908d71..c962b6bbaa 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -180,6 +180,7 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_register_global(GlobalProperty *prop); void qdev_prop_register_global_list(GlobalProperty *props); +int qdev_prop_check_global(void); void qdev_prop_set_globals(DeviceState *dev, Error **errp); void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, Error **errp); diff --git a/vl.c b/vl.c index 709d8cda8d..bda88f7b01 100644 --- a/vl.c +++ b/vl.c @@ -4532,6 +4532,8 @@ int main(int argc, char **argv, char **envp) } } + qdev_prop_check_global(); + if (incoming) { Error *local_err = NULL; qemu_start_incoming_migration(incoming, &local_err); From 711e2f1e9ecad845e142fdddbbf1e8037bce902b Mon Sep 17 00:00:00 2001 From: Don Slutz Date: Mon, 5 May 2014 14:03:07 -0400 Subject: [PATCH 10/10] qdev: Add test of qdev_prop_check_global This will generate a warning from "make check": ... GTESTER tests/test-qdev-global-props Warning: "-global dynamic-prop-type-bad.prop3=103" not used GTESTER tests/check-qom-interface ... If the warning is not generated, the test will fail. Signed-off-by: Don Slutz Acked-by: Michael S. Tsirkin --- tests/test-qdev-global-props.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index e4ad173d72..2bef04c76f 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -150,8 +150,10 @@ static void test_dynamic_globalprop(void) static GlobalProperty props[] = { { TYPE_DYNAMIC_PROPS, "prop1", "101" }, { TYPE_DYNAMIC_PROPS, "prop2", "102" }, + { TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", true }, {} }; + int all_used; qdev_prop_register_global_list(props); @@ -160,6 +162,8 @@ static void test_dynamic_globalprop(void) g_assert_cmpuint(mt->prop1, ==, 101); g_assert_cmpuint(mt->prop2, ==, 102); + all_used = qdev_prop_check_global(); + g_assert_cmpuint(all_used, ==, 1); } int main(int argc, char **argv)