mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-25 04:30:02 +00:00
pc migration fixes
Last minute fixes for migration. It seems that if we don't fix it now, fixing it in the next version will be even more painful ... Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJT13s+AAoJECgfDbjSjVRpvuUH/jPZBB+cq+xtGj/qdIcRboK1 72ASwi7LrbDROqCxnbhomsaWEbGYw2YgaEwLCt9VqSh9brSVPz1D9J5fG7G5PgOz eY4hs2EoUk7NmDZh4+0Oev/+1Yw2H+B3NlxrEe9lChsN9IzZBrmR8k4H5/I8DfHS EjDX9rj7bLXtnAz4gtuYtdMX+0A2tcYmUVnzzKeAfnMq9xTAiaAPoUxhOADHTtzA gkDYC7CajVC5OoV7xFdqBaUeL/bZL6S0fS/5bsCZi8XOtf7Gtf5YpvvM3hai64K3 Fd6K2ArNAbZaH9v49/6Ro+TkbpUPBywksYdhSYZ9fvaVtfDumbYqXaomxsPO+Ps= =zLfN -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging pc migration fixes Last minute fixes for migration. It seems that if we don't fix it now, fixing it in the next version will be even more painful ... Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Tue 29 Jul 2014 11:45:18 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: piix: set legacy table size for 1.7 acpi-build: tweak acpi migration limits pc: future-proof migration-compatibility of ACPI tables acpi-build: minor code cleanup pc: acpi: generate AML only for PCI0 devices if PCI bridge hotplug is disabled bios-tables-test: fix ASL normalization false positive pc: hack for migration compatibility from QEMU 2.0 acpi-dsdt: procedurally generate _PRT Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
04d1d6613f
@ -25,7 +25,9 @@
|
||||
#include <glib.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qom/cpu.h"
|
||||
#include "hw/i386/pc.h"
|
||||
@ -52,6 +54,16 @@
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
|
||||
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
|
||||
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
|
||||
* a little bit, there should be plenty of free space since the DSDT
|
||||
* shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1.
|
||||
*/
|
||||
#define ACPI_BUILD_LEGACY_CPU_AML_SIZE 97
|
||||
#define ACPI_BUILD_ALIGN_SIZE 0x1000
|
||||
|
||||
#define ACPI_BUILD_TABLE_SIZE 0x20000
|
||||
|
||||
typedef struct AcpiCpuInfo {
|
||||
DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
|
||||
} AcpiCpuInfo;
|
||||
@ -64,6 +76,7 @@ typedef struct AcpiMcfgInfo {
|
||||
typedef struct AcpiPmInfo {
|
||||
bool s3_disabled;
|
||||
bool s4_disabled;
|
||||
bool pcihp_bridge_en;
|
||||
uint8_t s4_val;
|
||||
uint16_t sci_int;
|
||||
uint8_t acpi_enable_cmd;
|
||||
@ -85,6 +98,7 @@ typedef struct AcpiBuildPciBusHotplugState {
|
||||
GArray *device_table;
|
||||
GArray *notify_table;
|
||||
struct AcpiBuildPciBusHotplugState *parent;
|
||||
bool pcihp_bridge_en;
|
||||
} AcpiBuildPciBusHotplugState;
|
||||
|
||||
static void acpi_get_dsdt(AcpiMiscInfo *info)
|
||||
@ -188,6 +202,9 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
||||
NULL);
|
||||
pm->gpe0_blk_len = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
|
||||
NULL);
|
||||
pm->pcihp_bridge_en =
|
||||
object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void acpi_get_misc_info(AcpiMiscInfo *info)
|
||||
@ -768,11 +785,13 @@ static void acpi_set_pci_info(void)
|
||||
}
|
||||
|
||||
static void build_pci_bus_state_init(AcpiBuildPciBusHotplugState *state,
|
||||
AcpiBuildPciBusHotplugState *parent)
|
||||
AcpiBuildPciBusHotplugState *parent,
|
||||
bool pcihp_bridge_en)
|
||||
{
|
||||
state->parent = parent;
|
||||
state->device_table = build_alloc_array();
|
||||
state->notify_table = build_alloc_array();
|
||||
state->pcihp_bridge_en = pcihp_bridge_en;
|
||||
}
|
||||
|
||||
static void build_pci_bus_state_cleanup(AcpiBuildPciBusHotplugState *state)
|
||||
@ -786,7 +805,7 @@ static void *build_pci_bus_begin(PCIBus *bus, void *parent_state)
|
||||
AcpiBuildPciBusHotplugState *parent = parent_state;
|
||||
AcpiBuildPciBusHotplugState *child = g_malloc(sizeof *child);
|
||||
|
||||
build_pci_bus_state_init(child, parent);
|
||||
build_pci_bus_state_init(child, parent, parent->pcihp_bridge_en);
|
||||
|
||||
return child;
|
||||
}
|
||||
@ -807,6 +826,14 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
||||
GArray *method;
|
||||
bool bus_hotplug_support = false;
|
||||
|
||||
/*
|
||||
* Skip bridge subtree creation if bridge hotplug is disabled
|
||||
* to make acpi tables compatible with legacy machine types.
|
||||
*/
|
||||
if (!child->pcihp_bridge_en && bus->parent_dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bus->parent_dev) {
|
||||
op = 0x82; /* DeviceOp */
|
||||
build_append_nameseg(bus_table, "S%.02X_",
|
||||
@ -844,6 +871,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
||||
PCIDeviceClass *pc;
|
||||
PCIDevice *pdev = bus->devices[i];
|
||||
int slot = PCI_SLOT(i);
|
||||
bool bridge_in_acpi;
|
||||
|
||||
if (!pdev) {
|
||||
continue;
|
||||
@ -853,7 +881,13 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
||||
pc = PCI_DEVICE_GET_CLASS(pdev);
|
||||
dc = DEVICE_GET_CLASS(pdev);
|
||||
|
||||
if (pc->class_id == PCI_CLASS_BRIDGE_ISA || pc->is_bridge) {
|
||||
/* When hotplug for bridges is enabled, bridges are
|
||||
* described in ACPI separately (see build_pci_bus_end).
|
||||
* In this case they aren't themselves hot-pluggable.
|
||||
*/
|
||||
bridge_in_acpi = pc->is_bridge && child->pcihp_bridge_en;
|
||||
|
||||
if (pc->class_id == PCI_CLASS_BRIDGE_ISA || bridge_in_acpi) {
|
||||
set_bit(slot, slot_device_system);
|
||||
}
|
||||
|
||||
@ -865,7 +899,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
|
||||
}
|
||||
}
|
||||
|
||||
if (!dc->hotpluggable || pc->is_bridge) {
|
||||
if (!dc->hotpluggable || bridge_in_acpi) {
|
||||
clear_bit(slot, slot_hotplug_enable);
|
||||
}
|
||||
}
|
||||
@ -1130,7 +1164,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||
}
|
||||
|
||||
build_pci_bus_state_init(&hotplug_state, NULL);
|
||||
build_pci_bus_state_init(&hotplug_state, NULL, pm->pcihp_bridge_en);
|
||||
|
||||
if (bus) {
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
@ -1440,13 +1474,14 @@ static
|
||||
void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
{
|
||||
GArray *table_offsets;
|
||||
unsigned facs, dsdt, rsdt;
|
||||
unsigned facs, ssdt, dsdt, rsdt;
|
||||
AcpiCpuInfo cpu;
|
||||
AcpiPmInfo pm;
|
||||
AcpiMiscInfo misc;
|
||||
AcpiMcfgInfo mcfg;
|
||||
PcPciInfo pci;
|
||||
uint8_t *u;
|
||||
size_t aml_len = 0;
|
||||
|
||||
acpi_get_cpu_info(&cpu);
|
||||
acpi_get_pm_info(&pm);
|
||||
@ -1474,13 +1509,20 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
dsdt = tables->table_data->len;
|
||||
build_dsdt(tables->table_data, tables->linker, &misc);
|
||||
|
||||
/* Count the size of the DSDT and SSDT, we will need it for legacy
|
||||
* sizing of ACPI tables.
|
||||
*/
|
||||
aml_len += tables->table_data->len - dsdt;
|
||||
|
||||
/* ACPI tables pointed to by RSDT */
|
||||
acpi_add_table(table_offsets, tables->table_data);
|
||||
build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt);
|
||||
|
||||
ssdt = tables->table_data->len;
|
||||
acpi_add_table(table_offsets, tables->table_data);
|
||||
build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci,
|
||||
guest_info);
|
||||
aml_len += tables->table_data->len - ssdt;
|
||||
|
||||
acpi_add_table(table_offsets, tables->table_data);
|
||||
build_madt(tables->table_data, tables->linker, &cpu, guest_info);
|
||||
@ -1513,14 +1555,53 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
/* RSDP is in FSEG memory, so allocate it separately */
|
||||
build_rsdp(tables->rsdp, tables->linker, rsdt);
|
||||
|
||||
/* We'll expose it all to Guest so align size to reduce
|
||||
/* We'll expose it all to Guest so we want to reduce
|
||||
* chance of size changes.
|
||||
* RSDP is small so it's easy to keep it immutable, no need to
|
||||
* bother with alignment.
|
||||
*
|
||||
* We used to align the tables to 4k, but of course this would
|
||||
* too simple to be enough. 4k turned out to be too small an
|
||||
* alignment very soon, and in fact it is almost impossible to
|
||||
* keep the table size stable for all (max_cpus, max_memory_slots)
|
||||
* combinations. So the table size is always 64k for pc-i440fx-2.1
|
||||
* and we give an error if the table grows beyond that limit.
|
||||
*
|
||||
* We still have the problem of migrating from "-M pc-i440fx-2.0". For
|
||||
* that, we exploit the fact that QEMU 2.1 generates _smaller_ tables
|
||||
* than 2.0 and we can always pad the smaller tables with zeros. We can
|
||||
* then use the exact size of the 2.0 tables.
|
||||
*
|
||||
* All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration.
|
||||
*/
|
||||
acpi_align_size(tables->table_data, 0x1000);
|
||||
if (guest_info->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 +
|
||||
ACPI_BUILD_LEGACY_CPU_AML_SIZE * max_cpus;
|
||||
int legacy_table_size =
|
||||
ROUND_UP(tables->table_data->len - aml_len + legacy_aml_len,
|
||||
ACPI_BUILD_ALIGN_SIZE);
|
||||
if (tables->table_data->len > legacy_table_size) {
|
||||
/* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
|
||||
error_report("Warning: migration may not work.");
|
||||
}
|
||||
g_array_set_size(tables->table_data, legacy_table_size);
|
||||
} else {
|
||||
/* Make sure we have a buffer in case we need to resize the tables. */
|
||||
if (tables->table_data->len > ACPI_BUILD_TABLE_SIZE / 2) {
|
||||
/* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */
|
||||
error_report("Warning: ACPI tables are larger than 64k.");
|
||||
error_report("Warning: migration may not work.");
|
||||
error_report("Warning: please remove CPUs, NUMA nodes, "
|
||||
"memory slots or PCI bridges.");
|
||||
}
|
||||
acpi_align_size(tables->table_data, ACPI_BUILD_TABLE_SIZE);
|
||||
}
|
||||
|
||||
acpi_align_size(tables->linker, 0x1000);
|
||||
acpi_align_size(tables->linker, ACPI_BUILD_ALIGN_SIZE);
|
||||
|
||||
/* Cleanup memory that's no longer used. */
|
||||
g_array_free(table_offsets, true);
|
||||
|
@ -181,57 +181,45 @@ DefinitionBlock (
|
||||
|
||||
Scope(\_SB) {
|
||||
Scope(PCI0) {
|
||||
Name(_PRT, Package() {
|
||||
/* PCI IRQ routing table, example from ACPI 2.0a specification,
|
||||
section 6.2.8.1 */
|
||||
/* Note: we provide the same info as the PCI routing
|
||||
table of the Bochs BIOS */
|
||||
Method (_PRT, 0) {
|
||||
Store(Package(128) {}, Local0)
|
||||
Store(Zero, Local1)
|
||||
While(LLess(Local1, 128)) {
|
||||
// slot = pin >> 2
|
||||
Store(ShiftRight(Local1, 2), Local2)
|
||||
|
||||
#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
|
||||
Package() { nr##ffff, 0, lnk0, 0 }, \
|
||||
Package() { nr##ffff, 1, lnk1, 0 }, \
|
||||
Package() { nr##ffff, 2, lnk2, 0 }, \
|
||||
Package() { nr##ffff, 3, lnk3, 0 }
|
||||
// lnk = (slot + pin) & 3
|
||||
Store(And(Add(Local1, Local2), 3), Local3)
|
||||
If (LEqual(Local3, 0)) {
|
||||
Store(Package(4) { Zero, Zero, LNKD, Zero }, Local4)
|
||||
}
|
||||
If (LEqual(Local3, 1)) {
|
||||
// device 1 is the power-management device, needs SCI
|
||||
If (LEqual(Local1, 4)) {
|
||||
Store(Package(4) { Zero, Zero, LNKS, Zero }, Local4)
|
||||
} Else {
|
||||
Store(Package(4) { Zero, Zero, LNKA, Zero }, Local4)
|
||||
}
|
||||
}
|
||||
If (LEqual(Local3, 2)) {
|
||||
Store(Package(4) { Zero, Zero, LNKB, Zero }, Local4)
|
||||
}
|
||||
If (LEqual(Local3, 3)) {
|
||||
Store(Package(4) { Zero, Zero, LNKC, Zero }, Local4)
|
||||
}
|
||||
|
||||
#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
|
||||
#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
|
||||
#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
|
||||
#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
|
||||
// Complete the interrupt routing entry:
|
||||
// Package(4) { 0x[slot]FFFF, [pin], [link], 0) }
|
||||
|
||||
prt_slot0(0x0000),
|
||||
/* Device 1 is power mgmt device, and can only use irq 9 */
|
||||
prt_slot(0x0001, LNKS, LNKB, LNKC, LNKD),
|
||||
prt_slot2(0x0002),
|
||||
prt_slot3(0x0003),
|
||||
prt_slot0(0x0004),
|
||||
prt_slot1(0x0005),
|
||||
prt_slot2(0x0006),
|
||||
prt_slot3(0x0007),
|
||||
prt_slot0(0x0008),
|
||||
prt_slot1(0x0009),
|
||||
prt_slot2(0x000a),
|
||||
prt_slot3(0x000b),
|
||||
prt_slot0(0x000c),
|
||||
prt_slot1(0x000d),
|
||||
prt_slot2(0x000e),
|
||||
prt_slot3(0x000f),
|
||||
prt_slot0(0x0010),
|
||||
prt_slot1(0x0011),
|
||||
prt_slot2(0x0012),
|
||||
prt_slot3(0x0013),
|
||||
prt_slot0(0x0014),
|
||||
prt_slot1(0x0015),
|
||||
prt_slot2(0x0016),
|
||||
prt_slot3(0x0017),
|
||||
prt_slot0(0x0018),
|
||||
prt_slot1(0x0019),
|
||||
prt_slot2(0x001a),
|
||||
prt_slot3(0x001b),
|
||||
prt_slot0(0x001c),
|
||||
prt_slot1(0x001d),
|
||||
prt_slot2(0x001e),
|
||||
prt_slot3(0x001f),
|
||||
})
|
||||
Store(Or(ShiftLeft(Local2, 16), 0xFFFF), Index(Local4, 0))
|
||||
Store(And(Local1, 3), Index(Local4, 1))
|
||||
Store(Local4, Index(Local0, Local1))
|
||||
|
||||
Increment(Local1)
|
||||
}
|
||||
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
||||
|
||||
Field(PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -61,6 +61,7 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static bool has_pci_info;
|
||||
static bool has_acpi_build = true;
|
||||
static int legacy_acpi_table_size;
|
||||
static bool smbios_defaults = true;
|
||||
static bool smbios_legacy_mode;
|
||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||
@ -163,6 +164,7 @@ static void pc_init1(MachineState *machine,
|
||||
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
|
||||
|
||||
guest_info->has_acpi_build = has_acpi_build;
|
||||
guest_info->legacy_acpi_table_size = legacy_acpi_table_size;
|
||||
|
||||
guest_info->has_pci_info = has_pci_info;
|
||||
guest_info->isapc_ram_fw = !pci_enabled;
|
||||
@ -297,6 +299,23 @@ static void pc_init_pci(MachineState *machine)
|
||||
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
{
|
||||
/* This value depends on the actual DSDT and SSDT compiled into
|
||||
* the source QEMU; unfortunately it depends on the binary and
|
||||
* not on the machine type, so we cannot make pc-i440fx-1.7 work on
|
||||
* both QEMU 1.7 and QEMU 2.0.
|
||||
*
|
||||
* Large variations cause migration to fail for more than one
|
||||
* consecutive value of the "-smp" maxcpus option.
|
||||
*
|
||||
* For small variations of the kind caused by different iasl versions,
|
||||
* the 4k rounding usually leaves slack. However, there could be still
|
||||
* one or two values that break. For QEMU 1.7 and QEMU 2.0 the
|
||||
* slack is only ~10 bytes before one "-smp maxcpus" value breaks!
|
||||
*
|
||||
* 6652 is valid for QEMU 2.0, the right value for pc-i440fx-1.7 on
|
||||
* QEMU 1.7 it is 6414. For RHEL/CentOS 7.0 it is 6418.
|
||||
*/
|
||||
legacy_acpi_table_size = 6652;
|
||||
smbios_legacy_mode = true;
|
||||
has_reserved_memory = false;
|
||||
}
|
||||
@ -307,6 +326,7 @@ static void pc_compat_1_7(MachineState *machine)
|
||||
smbios_defaults = false;
|
||||
gigabyte_align = false;
|
||||
option_rom_has_mr = true;
|
||||
legacy_acpi_table_size = 6414;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,11 @@ static void pc_q35_init(MachineState *machine)
|
||||
guest_info->has_acpi_build = has_acpi_build;
|
||||
guest_info->has_reserved_memory = has_reserved_memory;
|
||||
|
||||
/* 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 (smbios_defaults) {
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
|
@ -94,6 +94,7 @@ 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;
|
||||
};
|
||||
|
Binary file not shown.
@ -487,7 +487,11 @@ static GString *normalize_asl(gchar *asl_code)
|
||||
/* strip comments (different generation days) */
|
||||
comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
|
||||
if (comment) {
|
||||
asl = g_string_erase(asl, 0, comment + sizeof(COMMENT_END) - asl->str);
|
||||
comment += strlen(COMMENT_END);
|
||||
while (*comment == '\n') {
|
||||
comment++;
|
||||
}
|
||||
asl = g_string_erase(asl, 0, comment - asl->str);
|
||||
}
|
||||
|
||||
/* strip def block name (it has file path in it) */
|
||||
|
Loading…
Reference in New Issue
Block a user