From 2cef91cf4922cb1ade8882c1097966b090467bbb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 13 Jul 2017 19:42:54 +0300 Subject: [PATCH 01/10] tests: switch pxe and vm gen id tests to use kvm Speed up tests on host systems with kvm support. Cc: Paolo Bonzini Cc: Thomas Huth Cc: Laurent Vivier Signed-off-by: Michael S. Tsirkin Acked-by: Paolo Bonzini --- tests/pxe-test.c | 2 +- tests/vmgenid-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pxe-test.c b/tests/pxe-test.c index 34282d3704..cf6e225330 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -25,7 +25,7 @@ static void test_pxe_one(const char *params, bool ipv6) { char *args; - args = g_strdup_printf("-machine accel=tcg -nodefaults -boot order=n " + args = g_strdup_printf("-machine accel=kvm:tcg -nodefaults -boot order=n " "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s," "ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off", params); diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c index a49de9233b..3d5c1c3615 100644 --- a/tests/vmgenid-test.c +++ b/tests/vmgenid-test.c @@ -132,7 +132,7 @@ static char disk[] = "tests/vmgenid-test-disk-XXXXXX"; static char *guid_cmd_strdup(const char *guid) { - return g_strdup_printf("-machine accel=tcg " + return g_strdup_printf("-machine accel=kvm:tcg " "-device vmgenid,id=testvgid,guid=%s " "-drive id=hd0,if=none,file=%s,format=raw " "-device ide-hd,drive=hd0 ", From 08b9e0ba623c4468fe94026a9bdd086526ef62f0 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Wed, 5 Jul 2017 06:33:32 +0800 Subject: [PATCH 02/10] vhost: fix a memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost exists a call for g_file_get_contents, but not call g_free. Signed-off-by: Peng Hao Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- hw/virtio/vhost-backend.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index cb055e8f21..7f09efab8b 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -52,11 +52,13 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev) &s, NULL, NULL)) { uint64_t val = g_ascii_strtoull(s, NULL, 10); if (!((val == G_MAXUINT64 || !val) && errno)) { + g_free(s); return val; } error_report("ignoring invalid max_mem_regions value in vhost module:" " %s", s); } + g_free(s); return limit; } From 5df04f1762ef78c08fd69e19dcedf3d9ba8c9b86 Mon Sep 17 00:00:00 2001 From: Felipe Franciosi Date: Wed, 14 Jun 2017 18:44:38 +0100 Subject: [PATCH 03/10] vhost-user: fix legacy cross-endian configurations Currently, vhost-user does not implement any means for notifying the backend about guest endianess. This commit introduces a new message called VHOST_USER_SET_VRING_ENDIAN which is analogous to the ioctl() called VHOST_SET_VRING_ENDIAN used for kernel vhost backends. Such message is necessary for backends supporting legacy (pre-1.0) virtio devices running in big-endian guests. Signed-off-by: Felipe Franciosi Signed-off-by: Mike Cui --- docs/interop/vhost-user.txt | 16 ++++++++++++++++ hw/virtio/vhost-user.c | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index 481ab56e35..954771d0d8 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -326,6 +326,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_REPLY_ACK 3 #define VHOST_USER_PROTOCOL_F_MTU 4 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 +#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 Master message types -------------------- @@ -580,6 +581,21 @@ Master message types This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature has been successfully negotiated. + * VHOST_USER_SET_VRING_ENDIAN + + Id: 23 + Equivalent ioctl: VHOST_SET_VRING_ENDIAN + Master payload: vring state description + + Set the endianess of a VQ for legacy devices. Little-endian is indicated + with state.num set to 0 and big-endian is indicated with state.num set + to 1. Other values are invalid. + This request should be sent only when VHOST_USER_PROTOCOL_F_CROSS_ENDIAN + has been negotiated. + Backends that negotiated this feature should handle both endianesses + and expect this message once (per VQ) during device configuration + (ie. before the master starts the VQ). + Slave message types ------------------- diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2203011125..093675ed98 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -33,6 +33,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, VHOST_USER_PROTOCOL_F_NET_MTU = 4, VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5, + VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, VHOST_USER_PROTOCOL_F_MAX }; @@ -63,6 +64,7 @@ typedef enum VhostUserRequest { VHOST_USER_NET_SET_MTU = 20, VHOST_USER_SET_SLAVE_REQ_FD = 21, VHOST_USER_IOTLB_MSG = 22, + VHOST_USER_SET_VRING_ENDIAN = 23, VHOST_USER_MAX } VhostUserRequest; @@ -367,8 +369,25 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, static int vhost_user_set_vring_endian(struct vhost_dev *dev, struct vhost_vring_state *ring) { - error_report("vhost-user trying to send unhandled ioctl"); - return -1; + bool cross_endian = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CROSS_ENDIAN); + VhostUserMsg msg = { + .request = VHOST_USER_SET_VRING_ENDIAN, + .flags = VHOST_USER_VERSION, + .payload.state = *ring, + .size = sizeof(msg.payload.state), + }; + + if (!cross_endian) { + error_report("vhost-user trying to send unhandled ioctl"); + return -1; + } + + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + return -1; + } + + return 0; } static int vhost_set_vring(struct vhost_dev *dev, From 892721d91d9deb2affe4e61334b1dd1b43728f92 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 17 Jul 2017 17:02:29 +0800 Subject: [PATCH 04/10] intel_iommu: fix iova for pt IOMMUTLBEntry.iova is returned incorrectly on one PT path (though mostly we cannot really trigger this path, even if we do, we are mostly disgarding this value, so it didn't break anything). Fix it by converting the VTD_PAGE_MASK into the correct definition VTD_PAGE_MASK_4K, then remove VTD_PAGE_MASK. Fixes: b93130 ("intel_iommu: cleanup vtd_{do_}iommu_translate()") Signed-off-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 4 ++-- hw/i386/intel_iommu_internal.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index e398746b4b..e0b0498385 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1139,9 +1139,9 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, * Also, let's ignore IOTLB caching as well for PT devices. */ if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) { - entry->iova = addr & VTD_PAGE_MASK; + entry->iova = addr & VTD_PAGE_MASK_4K; entry->translated_addr = entry->iova; - entry->addr_mask = VTD_PAGE_MASK; + entry->addr_mask = ~VTD_PAGE_MASK_4K; entry->perm = IOMMU_RW; trace_vtd_translate_pt(source_id, entry->iova); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index f50ecd8b73..0e73a65bf2 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -384,7 +384,6 @@ typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo; /* Pagesize of VTD paging structures, including root and context tables */ #define VTD_PAGE_SHIFT 12 #define VTD_PAGE_SIZE (1ULL << VTD_PAGE_SHIFT) -#define VTD_PAGE_MASK (VTD_PAGE_SIZE - 1) #define VTD_PAGE_SHIFT_4K 12 #define VTD_PAGE_MASK_4K (~((1ULL << VTD_PAGE_SHIFT_4K) - 1)) From 07f7b73398de3b60f28301a9af2a2338710105c7 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 17 Jul 2017 17:02:30 +0800 Subject: [PATCH 05/10] intel_iommu: use access_flags for iotlb It was cached by read/write separately. Let's merge them. Signed-off-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 15 +++++++-------- include/hw/i386/intel_iommu.h | 3 +-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index e0b0498385..a7bf87a19e 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -237,8 +237,7 @@ out: 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, - uint32_t level) + uint8_t access_flags, uint32_t level) { VTDIOTLBEntry *entry = g_malloc(sizeof(*entry)); uint64_t *key = g_malloc(sizeof(*key)); @@ -253,8 +252,7 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, entry->gfn = gfn; entry->domain_id = domain_id; entry->slpte = slpte; - entry->read_flags = read_flags; - entry->write_flags = write_flags; + entry->access_flags = access_flags; 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); @@ -1087,6 +1085,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, bool is_fpd_set = false; bool reads = true; bool writes = true; + uint8_t access_flags; VTDIOTLBEntry *iotlb_entry; /* @@ -1101,8 +1100,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, trace_vtd_iotlb_page_hit(source_id, addr, iotlb_entry->slpte, iotlb_entry->domain_id); slpte = iotlb_entry->slpte; - reads = iotlb_entry->read_flags; - writes = iotlb_entry->write_flags; + access_flags = iotlb_entry->access_flags; page_mask = iotlb_entry->mask; goto out; } @@ -1172,13 +1170,14 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, } page_mask = vtd_slpt_level_page_mask(level); + access_flags = IOMMU_ACCESS_FLAG(reads, writes); vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte, - reads, writes, level); + access_flags, level); out: entry->iova = addr & page_mask; entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask; entry->addr_mask = ~page_mask; - entry->perm = IOMMU_ACCESS_FLAG(reads, writes); + entry->perm = access_flags; return true; error: diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 08d8a26d13..ac15e6be14 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -103,8 +103,7 @@ struct VTDIOTLBEntry { uint16_t domain_id; uint64_t slpte; uint64_t mask; - bool read_flags; - bool write_flags; + uint8_t access_flags; }; /* VT-d Source-ID Qualifier types */ From 2f6b38d171b11c2cedd294e2e7e50e110702f5ef Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 17 Jul 2017 16:45:27 +0200 Subject: [PATCH 06/10] accel: cleanup error output Only emit "XXX accelerator not found", if there are not further accelerators listed. eg accel=kvm:tcg doesn't print a "KVM accelerator not found" warning when it falls back to tcg, but a accel=kvm prints a warning, since no fallback is given. Suggested-by: Daniel P. Berrange Suggested-by: Paolo Bonzini Signed-off-by: Laurent Vivier Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Eric Blake Tested-by: Thomas Huth --- accel/accel.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/accel/accel.c b/accel/accel.c index fa8584488e..8ae40e1e13 100644 --- a/accel/accel.c +++ b/accel/accel.c @@ -33,6 +33,7 @@ #include "sysemu/qtest.h" #include "hw/xen/xen.h" #include "qom/object.h" +#include "qemu/error-report.h" static const TypeInfo accel_type = { .name = TYPE_ACCEL, @@ -69,19 +70,20 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms) void configure_accelerator(MachineState *ms) { - const char *p; + const char *accel, *p; char buf[10]; int ret; bool accel_initialised = false; bool init_failed = false; AccelClass *acc = NULL; - p = qemu_opt_get(qemu_get_machine_opts(), "accel"); - if (p == NULL) { + accel = qemu_opt_get(qemu_get_machine_opts(), "accel"); + if (accel == NULL) { /* Use the default "accelerator", tcg */ - p = "tcg"; + accel = "tcg"; } + p = accel; while (!accel_initialised && *p != '\0') { if (*p == ':') { p++; @@ -89,7 +91,6 @@ void configure_accelerator(MachineState *ms) p = get_opt_name(buf, sizeof(buf), p, ':'); acc = accel_find(buf); if (!acc) { - fprintf(stderr, "\"%s\" accelerator not found.\n", buf); continue; } if (acc->available && !acc->available()) { @@ -100,9 +101,8 @@ void configure_accelerator(MachineState *ms) ret = accel_init_machine(acc, ms); if (ret < 0) { init_failed = true; - fprintf(stderr, "failed to initialize %s: %s\n", - acc->name, - strerror(-ret)); + error_report("failed to initialize %s: %s", + acc->name, strerror(-ret)); } else { accel_initialised = true; } @@ -110,13 +110,13 @@ void configure_accelerator(MachineState *ms) if (!accel_initialised) { if (!init_failed) { - fprintf(stderr, "No accelerator found!\n"); + error_report("-machine accel=%s: No accelerator found", accel); } exit(1); } if (init_failed) { - fprintf(stderr, "Back to %s accelerator.\n", acc->name); + error_report("Back to %s accelerator", acc->name); } } From 91c38e08af93d7d9df5636e4d7747ce3eb7ff1fc Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 20 Jul 2017 17:35:36 +0100 Subject: [PATCH 07/10] tests/bios-tables-test: Compiler warning fix gcc 7.1.1 in fedora 26 moans about the: tables = g_new0(uint32_t, tables_nr) because it can't convince itself that tables_nr is positive. This is fallout from g_assert_cmpint no longer necessarily being no-return; replace it with a plain g_assert. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- tests/bios-tables-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 63da978f0b..564da45f65 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -108,7 +108,7 @@ static void test_acpi_rsdt_table(test_data *data) /* compute the table entries in rsdt */ tables_nr = (rsdt_table->length - sizeof(AcpiRsdtDescriptorRev1)) / sizeof(uint32_t); - g_assert_cmpint(tables_nr, >, 0); + g_assert(tables_nr > 0); /* get the addresses of the tables pointed by rsdt */ tables = g_new0(uint32_t, tables_nr); From 41d4e5ec9f77acaca706d00ee4baaf5324274da5 Mon Sep 17 00:00:00 2001 From: Yunjian Wang Date: Fri, 28 Jul 2017 09:50:53 +0800 Subject: [PATCH 08/10] vhost-user: fix watcher need be removed when vhost-user hotplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "nc" is freed after hotplug vhost-user, but the watcher is not removed. The QEMU crash when the watcher access the "nc" when socket disconnects. Program received signal SIGSEGV, Segmentation fault. #0 object_get_class (obj=obj@entry=0x2) at qom/object.c:750 #1 0x00007f9bb4180da1 in qemu_chr_fe_disconnect (be=) at chardev/char-fe.c:372 #2 0x00007f9bb40d1100 in net_vhost_user_watch (chan=, cond=, opaque=) at net/vhost-user.c:188 #3 0x00007f9baf97f99a in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 #4 0x00007f9bb41d7ebc in glib_pollfds_poll () at util/main-loop.c:213 #5 os_host_main_loop_wait (timeout=) at util/main-loop.c:261 #6 main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:515 #7 0x00007f9bb3e266a7 in main_loop () at vl.c:1917 #8 main (argc=, argv=, envp=) at vl.c:4786 Signed-off-by: Yunjian Wang Reviewed-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/vhost-user.c b/net/vhost-user.c index 36f32a2d84..c23927c912 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -151,6 +151,10 @@ static void vhost_user_cleanup(NetClientState *nc) s->vhost_net = NULL; } if (nc->queue_index == 0) { + if (s->watch) { + g_source_remove(s->watch); + s->watch = 0; + } qemu_chr_fe_deinit(&s->chr, true); } From 208fa0e43645edd0b0d8f838857dfc79daff40a8 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 28 Jul 2017 11:09:05 +0200 Subject: [PATCH 09/10] pc: make 'pc.rom' readonly when machine has PCI enabled looking at bios ROM mapping in QEMU it seems that only isapc (i.e. not PCI enabled machine) requires ROM being mapped as RW in other cases BIOS is mapped as RO. Do the same for option ROM 'pc.rom' when machine has PCI enabled. As useful side-effect pc.rom MemoryRegion stops being put in vhost memory map (filtered out by vhost_section()), which reduces number of entries by 1. Coincidentally it fixes migration failure reported in "[PATCH V2] vhost: fix a migration failed because of vhost region merge" where following destination CLI with /sys/module/vhost/parameters/max_mem_regions = 8 export DIMMSCOUNT=6 QEMU -enable-kvm \ -netdev type=tap,id=guest0,vhost=on,script=no,vhostforce \ -device virtio-net-pci,netdev=guest0 \ -m 256,slots=256,maxmem=2G \ `i=0; while [ $i -lt $DIMMSCOUNT ]; do echo \ "-object memory-backend-ram,id=m$i,size=128M \ -device pc-dimm,id=d$i,memdev=m$i"; i=$(($i + 1)); \ done` will fail to startup with error: "-device pc-dimm,id=d5,memdev=m5: a used vhost backend has no free memory slots left" while it's possible to add the 6th DIMM during hotplug on source. Issue is caused by the fact that number of entries in vhost map is bigger on 1 entry, when -device is processed, than after guest boots up, and that offending entry belongs to 'pc.rom', it's not like vhost intends to do IO in ROM range so making it RO hides region from vhost and makes number of entries in vhost memory map at -device/machine_done time match number of entries after guest boots. Signed-off-by: Igor Mammedov Reported-by: Peng Hao Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 22e16031b0..59435390ba 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1443,6 +1443,9 @@ void pc_memory_init(PCMachineState *pcms, option_rom_mr = g_malloc(sizeof(*option_rom_mr)); memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, &error_fatal); + if (pcmc->pci_enabled) { + memory_region_set_readonly(option_rom_mr, true); + } memory_region_add_subregion_overlap(rom_memory, PC_ROM_MIN_VGA, option_rom_mr, From 3a3fcc75f92ab0d71ba0e7511af7dc575c4b4f6c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 24 Jul 2017 15:50:20 +0200 Subject: [PATCH 10/10] pc: acpi: force FADT rev1 for 440fx based machine types w2k used to boot on QEMU until revision of FADT has been bumped to rev3 (commit 77af8a2b hw/i386: Use Rev3 FADT (ACPI 2.0) instead of Rev1 to improve guest OS support.) Keep PC machine at rev1 to remain compatible and Q35 at rev3 where w2k isn't supported anyway so OSX could run as well. Signed-off-by: Igor Mammedov Tested-by: John Arbuckle Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 6b7bade183..b9c245c9bb 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -90,6 +90,7 @@ typedef struct AcpiMcfgInfo { } AcpiMcfgInfo; typedef struct AcpiPmInfo { + bool force_rev1_fadt; bool s3_disabled; bool s4_disabled; bool pcihp_bridge_en; @@ -129,10 +130,13 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) Object *obj = NULL; QObject *o; + pm->force_rev1_fadt = false; pm->cpu_hp_io_base = 0; pm->pcihp_io_base = 0; pm->pcihp_io_len = 0; if (piix) { + /* w2k requires FADT(rev1) or it won't boot, keep PC compatible */ + pm->force_rev1_fadt = true; obj = piix; pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE; pm->pcihp_io_base = @@ -304,6 +308,9 @@ static void fadt_setup(AcpiFadtDescriptorRev3 *fadt, AcpiPmInfo *pm) fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL); } fadt->century = RTC_CENTURY; + if (pm->force_rev1_fadt) { + return; + } fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_RESET_REG_SUP); fadt->reset_value = 0xf; @@ -342,6 +349,8 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data; unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data; unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data; + int fadt_size = sizeof(*fadt); + int rev = 3; /* FACS address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, @@ -353,12 +362,17 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt), ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt), - ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); + if (pm->force_rev1_fadt) { + rev = 1; + fadt_size = offsetof(typeof(*fadt), reset_register); + } else { + bios_linker_loader_add_pointer(linker, + ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt), + ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); + } build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 3, oem_id, oem_table_id); + (void *)fadt, "FACP", fadt_size, rev, oem_id, oem_table_id); } void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,