#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qapi/qmp/qnum.h"
#include "acpi-build.h"
#include "qemu-common.h"
#include "qemu/bitmap.h"
#include "qemu/error-report.h"
#include "hw/pci/pci.h"
#include "qom/cpu.h"
-#include "hw/i386/pc.h"
#include "target/i386/cpu.h"
+#include "hw/misc/pvpanic.h"
#include "hw/timer/hpet.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
-#include "qapi/qmp/qint.h"
#include "qom/qom-qobject.h"
#include "hw/i386/amd_iommu.h"
#include "hw/i386/intel_iommu.h"
} AcpiMcfgInfo;
typedef struct AcpiPmInfo {
+ bool force_rev1_fadt;
bool s3_disabled;
bool s4_disabled;
bool pcihp_bridge_en;
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 =
- object_property_get_int(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
+ object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
pm->pcihp_io_len =
- object_property_get_int(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
+ object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL);
}
if (lpc) {
obj = lpc;
/* Fill in optional s3/s4 related properties */
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
if (o) {
- pm->s3_disabled = qint_get_int(qobject_to_qint(o));
+ pm->s3_disabled = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s3_disabled = false;
}
qobject_decref(o);
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL);
if (o) {
- pm->s4_disabled = qint_get_int(qobject_to_qint(o));
+ pm->s4_disabled = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s4_disabled = false;
}
qobject_decref(o);
o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL);
if (o) {
- pm->s4_val = qint_get_int(qobject_to_qint(o));
+ pm->s4_val = qnum_get_uint(qobject_to_qnum(o));
} else {
pm->s4_val = false;
}
qobject_decref(o);
/* Fill in mandatory properties */
- pm->sci_int = object_property_get_int(obj, ACPI_PM_PROP_SCI_INT, NULL);
-
- pm->acpi_enable_cmd = object_property_get_int(obj,
- ACPI_PM_PROP_ACPI_ENABLE_CMD,
- NULL);
- pm->acpi_disable_cmd = object_property_get_int(obj,
- ACPI_PM_PROP_ACPI_DISABLE_CMD,
- NULL);
- pm->io_base = object_property_get_int(obj, ACPI_PM_PROP_PM_IO_BASE,
- NULL);
- pm->gpe0_blk = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK,
+ pm->sci_int = object_property_get_uint(obj, ACPI_PM_PROP_SCI_INT, NULL);
+
+ pm->acpi_enable_cmd = object_property_get_uint(obj,
+ ACPI_PM_PROP_ACPI_ENABLE_CMD,
+ NULL);
+ pm->acpi_disable_cmd =
+ object_property_get_uint(obj,
+ ACPI_PM_PROP_ACPI_DISABLE_CMD,
+ NULL);
+ pm->io_base = object_property_get_uint(obj, ACPI_PM_PROP_PM_IO_BASE,
NULL);
- pm->gpe0_blk_len = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
- NULL);
+ pm->gpe0_blk = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK,
+ NULL);
+ pm->gpe0_blk_len = object_property_get_uint(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
+ NULL);
pm->pcihp_bridge_en =
object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
NULL);
}
info->has_hpet = hpet_find();
- info->tpm_version = tpm_get_version();
+ info->tpm_version = tpm_get_version(tpm_find());
info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_port();
}
g_assert(pci_host);
range_set_bounds1(hole,
- object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE_START,
- NULL),
- object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE_END,
- NULL));
+ object_property_get_uint(pci_host,
+ PCI_HOST_PROP_PCI_HOLE_START,
+ NULL),
+ object_property_get_uint(pci_host,
+ PCI_HOST_PROP_PCI_HOLE_END,
+ NULL));
range_set_bounds1(hole64,
- object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE64_START,
- NULL),
- object_property_get_int(pci_host,
- PCI_HOST_PROP_PCI_HOLE64_END,
- NULL));
+ object_property_get_uint(pci_host,
+ PCI_HOST_PROP_PCI_HOLE64_START,
+ NULL),
+ object_property_get_uint(pci_host,
+ PCI_HOST_PROP_PCI_HOLE64_END,
+ NULL));
}
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
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;
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,
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,
table_data->len - madt_start, 1, NULL, NULL);
}
-/* Assign BSEL property to all buses. In the future, this can be changed
- * to only assign to buses that support hotplug.
- */
-static void *acpi_set_bsel(PCIBus *bus, void *opaque)
-{
- unsigned *bsel_alloc = opaque;
- unsigned *bus_bsel;
-
- if (qbus_is_hotpluggable(BUS(bus))) {
- bus_bsel = g_malloc(sizeof *bus_bsel);
-
- *bus_bsel = (*bsel_alloc)++;
- object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, &error_abort);
- }
-
- return bsel_alloc;
-}
-
-static void acpi_set_pci_info(void)
-{
- PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
- unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT;
-
- if (bus) {
- /* Scan all PCI buses. Set property to enable acpi based hotplug. */
- pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
- }
-}
-
static void build_append_pcihp_notify_entry(Aml *method, int slot)
{
Aml *if_ctx;
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
if (bsel) {
- int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
+ uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
/* If bus supports hotplug select it and notify about local events */
if (bsel) {
- int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
+ uint64_t bsel_val = qnum_get_uint(qobject_to_qnum(bsel));
+
aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
aml_append(method,
aml_call2("DVNT", aml_name("PCIU"), aml_int(1) /* Device Check */)
/*
* Always allow native PME, AER (no dependencies)
- * Never allow SHPC (no SHPC controller in this system)
+ * Allow SHPC (PCI bridges can have SHPC controller)
*/
- aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1D), a_ctrl));
+ aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
/* Unknown revision */
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, aml_int(0xae00), 0x0c));
- aml_append(sb_scope,
- aml_operation_region("PCSB", AML_SYSTEM_IO, aml_int(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")));
}
}
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
+ if (TPM_IS_TIS(tpm_find())) {
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
}
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
- if (misc->tpm_version != TPM_VERSION_UNSPEC) {
+ if (TPM_IS_TIS(tpm_find())) {
dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
aml_append(sb_scope, scope);
}
}
+
+ if (TPM_IS_CRB(tpm_find())) {
+ dev = aml_device("TPM");
+ aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
+ crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(TPM_CRB_ADDR_BASE,
+ TPM_CRB_ADDR_SIZE, AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+
+ method = aml_method("_STA", 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_return(aml_int(0x0f)));
+ aml_append(dev, method);
+
+ aml_append(sb_scope, dev);
+ }
+
aml_append(dsdt, sb_scope);
/* copy AML table into ACPI tables blob and patch header there */
}
static void
-build_tpm2(GArray *table_data, BIOSLinker *linker)
+build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
{
- Acpi20TPM2 *tpm2_ptr;
-
- tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
+ Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
+ unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address);
+ unsigned log_addr_offset =
+ (char *)&tpm2_ptr->log_area_start_address - table_data->data;
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
- tpm2_ptr->control_area_address = cpu_to_le64(0);
- tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
+ if (TPM_IS_TIS(tpm_find())) {
+ tpm2_ptr->control_area_address = cpu_to_le64(0);
+ tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
+ } else if (TPM_IS_CRB(tpm_find())) {
+ tpm2_ptr->control_area_address = cpu_to_le64(TPM_CRB_ADDR_CTRL);
+ tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_CRB);
+ } else {
+ g_warn_if_reached();
+ }
+
+ tpm2_ptr->log_area_minimum_length =
+ cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE);
+ /* log area start address to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
+ log_addr_offset, log_addr_size,
+ ACPI_BUILD_TPMLOG_FILE, 0);
build_header(linker, table_data,
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
}
+#define HOLE_640K_START (640 * 1024)
+#define HOLE_640K_END (1024 * 1024)
+
static void
build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
srat->reserved1 = cpu_to_le32(1);
for (i = 0; i < apic_ids->len; i++) {
- int node_id = apic_ids->cpus[i].props.has_node_id ?
- apic_ids->cpus[i].props.node_id : 0;
+ int node_id = apic_ids->cpus[i].props.node_id;
uint32_t apic_id = apic_ids->cpus[i].arch_id;
if (apic_id < 255) {
next_base = 0;
numa_start = table_data->len;
- numamem = acpi_data_push(table_data, sizeof *numamem);
- build_srat_memory(numamem, 0, 640 * 1024, 0, MEM_AFFINITY_ENABLED);
- next_base = 1024 * 1024;
for (i = 1; i < pcms->numa_nodes + 1; ++i) {
mem_base = next_base;
mem_len = pcms->node_mem[i - 1];
- if (i == 1) {
- mem_len -= 1024 * 1024;
- }
next_base = mem_base + mem_len;
+ /* Cut out the 640K hole */
+ if (mem_base <= HOLE_640K_START &&
+ next_base > HOLE_640K_START) {
+ mem_len -= next_base - HOLE_640K_START;
+ if (mem_len > 0) {
+ numamem = acpi_data_push(table_data, sizeof *numamem);
+ build_srat_memory(numamem, mem_base, mem_len, i - 1,
+ MEM_AFFINITY_ENABLED);
+ }
+
+ /* Check for the rare case: 640K < RAM < 1M */
+ if (next_base <= HOLE_640K_END) {
+ next_base = HOLE_640K_END;
+ continue;
+ }
+ mem_base = HOLE_640K_END;
+ mem_len = next_base - HOLE_640K_END;
+ }
+
/* Cut out the ACPI_PCI hole */
if (mem_base <= pcms->below_4g_mem_size &&
next_base > pcms->below_4g_mem_size) {
}
mem_base = 1ULL << 32;
mem_len = next_base - pcms->below_4g_mem_size;
- next_base += (1ULL << 32) - pcms->below_4g_mem_size;
+ next_base = mem_base + mem_len;
}
numamem = acpi_data_push(table_data, sizeof *numamem);
build_srat_memory(numamem, mem_base, mem_len, i - 1,
AcpiDmarDeviceScope *scope = NULL;
/* Root complex IOAPIC use one path[0] only */
size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]);
+ IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
assert(iommu);
if (iommu->intr_supported) {
}
dmar = acpi_data_push(table_data, sizeof(*dmar));
- dmar->host_address_width = VTD_HOST_ADDRESS_WIDTH - 1;
+ dmar->host_address_width = intel_iommu->aw_bits - 1;
dmar->flags = dmar_flags;
/* DMAR Remapping Hardware Unit Definition structure */
if (!o) {
return false;
}
- mcfg->mcfg_base = qint_get_int(qobject_to_qint(o));
+ mcfg->mcfg_base = qnum_get_uint(qobject_to_qnum(o));
qobject_decref(o);
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
assert(o);
- mcfg->mcfg_size = qint_get_int(qobject_to_qint(o));
+ mcfg->mcfg_size = qnum_get_uint(qobject_to_qnum(o));
qobject_decref(o);
return true;
}
if (misc.tpm_version == TPM_VERSION_2_0) {
acpi_add_table(table_offsets, tables_blob);
- build_tpm2(tables_blob, tables->linker);
+ build_tpm2(tables_blob, tables->linker, tables->tcpalog);
}
}
if (pcms->numa_nodes) {
ACPI_BUILD_ALIGN_SIZE);
if (tables_blob->len > legacy_table_size) {
/* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
- error_report("Warning: migration may not work.");
+ warn_report("ACPI table size %u exceeds %d bytes,"
+ " migration may not work",
+ tables_blob->len, legacy_table_size);
+ error_printf("Try removing CPUs, NUMA nodes, memory slots"
+ " or PCI bridges.");
}
g_array_set_size(tables_blob, legacy_table_size);
} else {
/* Make sure we have a buffer in case we need to resize the tables. */
if (tables_blob->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.");
+ warn_report("ACPI table size %u exceeds %d bytes,"
+ " migration may not work",
+ tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
+ error_printf("Try removing CPUs, NUMA nodes, memory slots"
+ " or PCI bridges.");
}
acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
}
build_state = g_malloc0(sizeof *build_state);
- acpi_set_pci_info();
-
acpi_build_tables_init(&tables);
acpi_build(&tables, MACHINE(pcms));
build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
- acpi_build_update, build_state,
+ acpi_build_update, NULL, build_state,
build_state->rsdp, rsdp_size, true);
build_state->rsdp_mr = NULL;
} else {