aboutsummaryrefslogtreecommitdiff
path: root/hw/i386
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-10-05 14:35:29 -0700
committerRichard Henderson <richard.henderson@linaro.org>2021-10-05 14:35:29 -0700
commit274f9a381cd334118e9c84afb3285fe1da97cf87 (patch)
treecc11a62e136ceb21921c80d3533d9deb56ff7caa /hw/i386
parent08a9b68dc033c9826da89f84202e547beadd92f0 (diff)
parent64bc656decc0fdf59e23753de8940c744b39b586 (diff)
downloadqemu-274f9a381cd334118e9c84afb3285fe1da97cf87.zip
qemu-274f9a381cd334118e9c84afb3285fe1da97cf87.tar.gz
qemu-274f9a381cd334118e9c84afb3285fe1da97cf87.tar.bz2
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc,pci,virtio: features, fixes A huge acpi refactoring. Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Tue 05 Oct 2021 02:31:11 PM PDT # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] * remotes/mst/tags/for_upstream: (47 commits) hw/i386/amd_iommu: Add description/category to TYPE_AMD_IOMMU_PCI hw/i386/amd_iommu: Rename SysBus specific functions as amdvi_sysbus_X() hw/i386/amd_iommu: Rename amdviPCI TypeInfo nvdimm: release the correct device list virtio-balloon: Fix page-poison subsection name bios-tables-test: Update ACPI DSDT table golden blobs for q35 hw/i386/acpi: fix conflicting IO address range for acpi pci hotplug in q35 bios-tables-test: allow changes in DSDT ACPI tables for q35 acpi: AcpiGenericAddress no longer used to map/access fields of MMIO, drop packed attribute acpi: remove no longer used build_header() acpi: build_facs: use build_append_int_noprefix() API to compose table acpi: arm/virt: build_gtdt: use acpi_table_begin()/acpi_table_end() instead of build_header() acpi: arm/virt: build_spcr: use acpi_table_begin()/acpi_table_end() instead of build_header() acpi: arm/virt: build_spcr: fix invalid cast acpi: arm/virt: convert build_iort() to endian agnostic build_append_FOO() API acpi: arm: virt: build_iort: use acpi_table_begin()/acpi_table_end() instead of build_header() acpi: arm: virt: build_dsdt: use acpi_table_begin()/acpi_table_end() instead of build_header() acpi: build_dsdt_microvm: use acpi_table_begin()/acpi_table_end() instead of build_header() acpi: arm/virt: madt: use build_append_int_noprefix() API to compose MADT table acpi: x86: madt: use build_append_int_noprefix() API to compose MADT table ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw/i386')
-rw-r--r--hw/i386/acpi-build.c294
-rw-r--r--hw/i386/acpi-common.c160
-rw-r--r--hw/i386/acpi-microvm.c13
-rw-r--r--hw/i386/amd_iommu.c41
4 files changed, 277 insertions, 231 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index f4d6ae3..81418b7 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -345,13 +345,23 @@ static void acpi_align_size(GArray *blob, unsigned align)
g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
}
-/* FACS */
+/*
+ * ACPI spec 1.0b,
+ * 5.2.6 Firmware ACPI Control Structure
+ */
static void
build_facs(GArray *table_data)
{
- AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs);
- memcpy(&facs->signature, "FACS", 4);
- facs->length = cpu_to_le32(sizeof(*facs));
+ const char *sig = "FACS";
+ const uint8_t reserved[40] = {};
+
+ g_array_append_vals(table_data, sig, 4); /* Signature */
+ build_append_int_noprefix(table_data, 64, 4); /* Length */
+ build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
+ build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
+ build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
+ build_append_int_noprefix(table_data, 0, 4); /* Flags */
+ g_array_append_vals(table_data, reserved, 40); /* Reserved */
}
static void build_append_pcihp_notify_entry(Aml *method, int slot)
@@ -1405,12 +1415,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
#endif
int i;
VMBusBridge *vmbus_bridge = vmbus_bridge_find();
+ AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = x86ms->oem_id,
+ .oem_table_id = x86ms->oem_table_id };
+ acpi_table_begin(&table, table_data);
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");
@@ -1867,70 +1877,87 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* 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, x86ms->oem_id, x86ms->oem_table_id);
+ acpi_table_end(linker, &table);
free_aml_allocator();
}
+/*
+ * IA-PC HPET (High Precision Event Timers) Specification (Revision: 1.0a)
+ * 3.2.4The ACPI 2.0 HPET Description Table (HPET)
+ */
static void
build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
- Acpi20Hpet *hpet;
- int hpet_start = table_data->len;
+ AcpiTable table = { .sig = "HPET", .rev = 1,
+ .oem_id = oem_id, .oem_table_id = oem_table_id };
- hpet = acpi_data_push(table_data, sizeof(*hpet));
+ acpi_table_begin(&table, table_data);
/* Note timer_block_id value must be kept in sync with value advertised by
* emulated hpet
*/
- hpet->timer_block_id = cpu_to_le32(0x8086a201);
- hpet->addr.address = cpu_to_le64(HPET_BASE);
- build_header(linker, table_data,
- (void *)(table_data->data + hpet_start),
- "HPET", sizeof(*hpet), 1, oem_id, oem_table_id);
+ /* Event Timer Block ID */
+ build_append_int_noprefix(table_data, 0x8086a201, 4);
+ /* BASE_ADDRESS */
+ build_append_gas(table_data, AML_AS_SYSTEM_MEMORY, 0, 0, 0, HPET_BASE);
+ /* HPET Number */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Main Counter Minimum Clock_tick in Periodic Mode */
+ build_append_int_noprefix(table_data, 0, 2);
+ /* Page Protection And OEM Attribute */
+ build_append_int_noprefix(table_data, 0, 1);
+ acpi_table_end(linker, &table);
}
#ifdef CONFIG_TPM
+/*
+ * TCPA Description Table
+ *
+ * Following Level 00, Rev 00.37 of specs:
+ * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification
+ * 7.1.2 ACPI Table Layout
+ */
static void
build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
const char *oem_id, const char *oem_table_id)
{
- int tcpa_start = table_data->len;
- Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa);
- unsigned log_addr_size = sizeof(tcpa->log_area_start_address);
- unsigned log_addr_offset =
- (char *)&tcpa->log_area_start_address - table_data->data;
-
- tcpa->platform_class = cpu_to_le16(TPM_TCPA_ACPI_CLASS_CLIENT);
- tcpa->log_area_minimum_length = cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE);
- acpi_data_push(tcpalog, le32_to_cpu(tcpa->log_area_minimum_length));
+ unsigned log_addr_offset;
+ AcpiTable table = { .sig = "TCPA", .rev = 2,
+ .oem_id = oem_id, .oem_table_id = oem_table_id };
+
+ acpi_table_begin(&table, table_data);
+ /* Platform Class */
+ build_append_int_noprefix(table_data, TPM_TCPA_ACPI_CLASS_CLIENT, 2);
+ /* Log Area Minimum Length (LAML) */
+ build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4);
+ /* Log Area Start Address (LASA) */
+ log_addr_offset = table_data->len;
+ build_append_int_noprefix(table_data, 0, 8);
+ /* allocate/reserve space for TPM log area */
+ acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1,
false /* high memory */);
-
/* 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);
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
+ log_addr_offset, 8, ACPI_BUILD_TPMLOG_FILE, 0);
- build_header(linker, table_data,
- (void *)(table_data->data + tcpa_start),
- "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id);
+ acpi_table_end(linker, &table);
}
#endif
#define HOLE_640K_START (640 * KiB)
#define HOLE_640K_END (1 * MiB)
+/*
+ * ACPI spec, Revision 3.0
+ * 5.2.15 System Resource Affinity Table (SRAT)
+ */
static void
build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
- AcpiSystemResourceAffinityTable *srat;
- AcpiSratMemoryAffinity *numamem;
-
int i;
- int srat_start, numa_start, slots;
+ int numa_mem_start, slots;
uint64_t mem_len, mem_base, next_base;
MachineClass *mc = MACHINE_GET_CLASS(machine);
X86MachineState *x86ms = X86_MACHINE(machine);
@@ -1941,45 +1968,53 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
ram_addr_t hotpluggable_address_space_size =
object_property_get_int(OBJECT(pcms), PC_MACHINE_DEVMEM_REGION_SIZE,
NULL);
+ AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = x86ms->oem_id,
+ .oem_table_id = x86ms->oem_table_id };
- srat_start = table_data->len;
-
- srat = acpi_data_push(table_data, sizeof *srat);
- srat->reserved1 = cpu_to_le32(1);
+ acpi_table_begin(&table, table_data);
+ build_append_int_noprefix(table_data, 1, 4); /* Reserved */
+ build_append_int_noprefix(table_data, 0, 8); /* Reserved */
for (i = 0; i < apic_ids->len; i++) {
int node_id = apic_ids->cpus[i].props.node_id;
uint32_t apic_id = apic_ids->cpus[i].arch_id;
if (apic_id < 255) {
- AcpiSratProcessorAffinity *core;
-
- core = acpi_data_push(table_data, sizeof *core);
- core->type = ACPI_SRAT_PROCESSOR_APIC;
- core->length = sizeof(*core);
- core->local_apic_id = apic_id;
- core->proximity_lo = node_id;
- memset(core->proximity_hi, 0, 3);
- core->local_sapic_eid = 0;
- core->flags = cpu_to_le32(1);
+ /* 5.2.15.1 Processor Local APIC/SAPIC Affinity Structure */
+ build_append_int_noprefix(table_data, 0, 1); /* Type */
+ build_append_int_noprefix(table_data, 16, 1); /* Length */
+ /* Proximity Domain [7:0] */
+ build_append_int_noprefix(table_data, node_id, 1);
+ build_append_int_noprefix(table_data, apic_id, 1); /* APIC ID */
+ /* Flags, Table 5-36 */
+ build_append_int_noprefix(table_data, 1, 4);
+ build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
+ /* Proximity Domain [31:8] */
+ build_append_int_noprefix(table_data, 0, 3);
+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */
} else {
- AcpiSratProcessorX2ApicAffinity *core;
-
- core = acpi_data_push(table_data, sizeof *core);
- core->type = ACPI_SRAT_PROCESSOR_x2APIC;
- core->length = sizeof(*core);
- core->x2apic_id = cpu_to_le32(apic_id);
- core->proximity_domain = cpu_to_le32(node_id);
- core->flags = cpu_to_le32(1);
+ /*
+ * ACPI spec, Revision 4.0
+ * 5.2.16.3 Processor Local x2APIC Affinity Structure
+ */
+ build_append_int_noprefix(table_data, 2, 1); /* Type */
+ build_append_int_noprefix(table_data, 24, 1); /* Length */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ /* Proximity Domain */
+ build_append_int_noprefix(table_data, node_id, 4);
+ build_append_int_noprefix(table_data, apic_id, 4); /* X2APIC ID */
+ /* Flags, Table 5-39 */
+ build_append_int_noprefix(table_data, 1 /* Enabled */, 4);
+ build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
+ build_append_int_noprefix(table_data, 0, 4); /* Reserved */
}
}
-
/* the memory map is a bit tricky, it contains at least one hole
* from 640k-1M and possibly another one from 3.5G-4G.
*/
next_base = 0;
- numa_start = table_data->len;
+ numa_mem_start = table_data->len;
for (i = 1; i < nb_numa_nodes + 1; ++i) {
mem_base = next_base;
@@ -1991,8 +2026,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
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,
+ build_srat_memory(table_data, mem_base, mem_len, i - 1,
MEM_AFFINITY_ENABLED);
}
@@ -2010,8 +2044,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
next_base > x86ms->below_4g_mem_size) {
mem_len -= next_base - x86ms->below_4g_mem_size;
if (mem_len > 0) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- build_srat_memory(numamem, mem_base, mem_len, i - 1,
+ build_srat_memory(table_data, mem_base, mem_len, i - 1,
MEM_AFFINITY_ENABLED);
}
mem_base = 1ULL << 32;
@@ -2020,8 +2053,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
}
if (mem_len > 0) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- build_srat_memory(numamem, mem_base, mem_len, i - 1,
+ build_srat_memory(table_data, mem_base, mem_len, i - 1,
MEM_AFFINITY_ENABLED);
}
}
@@ -2030,10 +2062,15 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
nvdimm_build_srat(table_data);
}
- slots = (table_data->len - numa_start) / sizeof *numamem;
+ /*
+ * TODO: this part is not in ACPI spec and current linux kernel boots fine
+ * without these entries. But I recall there were issues the last time I
+ * tried to remove it with some ancient guest OS, however I can't remember
+ * what that was so keep this around for now
+ */
+ slots = (table_data->len - numa_mem_start) / 40 /* mem affinity len */;
for (; slots < nb_numa_nodes + 2; slots++) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
+ build_srat_memory(table_data, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
}
/*
@@ -2045,17 +2082,12 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
* providing _PXM method if necessary.
*/
if (hotpluggable_address_space_size) {
- numamem = acpi_data_push(table_data, sizeof *numamem);
- build_srat_memory(numamem, machine->device_memory->base,
+ build_srat_memory(table_data, machine->device_memory->base,
hotpluggable_address_space_size, nb_numa_nodes - 1,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
}
- build_header(linker, table_data,
- (void *)(table_data->data + srat_start),
- "SRAT",
- table_data->len - srat_start, 1, x86ms->oem_id,
- x86ms->oem_table_id);
+ acpi_table_end(linker, &table);
}
/*
@@ -2064,8 +2096,9 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
static void
insert_scope(PCIBus *bus, PCIDevice *dev, void *opaque)
{
+ const size_t device_scope_size = 6 /* device scope structure */ +
+ 2 /* 1 path entry */;
GArray *scope_blob = opaque;
- AcpiDmarDeviceScope *scope = NULL;
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
/* Dmar Scope Type: 0x02 for PCI Bridge */
@@ -2076,8 +2109,7 @@ insert_scope(PCIBus *bus, PCIDevice *dev, void *opaque)
}
/* length */
- build_append_int_noprefix(scope_blob,
- sizeof(*scope) + sizeof(scope->path[0]), 1);
+ build_append_int_noprefix(scope_blob, device_scope_size, 1);
/* reserved */
build_append_int_noprefix(scope_blob, 0, 2);
/* enumeration_id */
@@ -2109,26 +2141,26 @@ dmar_host_bridges(Object *obj, void *opaque)
}
/*
- * VT-d spec 8.1 DMA Remapping Reporting Structure
- * (version Oct. 2014 or later)
+ * Intel ® Virtualization Technology for Directed I/O
+ * Architecture Specification. Revision 3.3
+ * 8.1 DMA Remapping Reporting Structure
*/
static void
build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
- int dmar_start = table_data->len;
-
- AcpiTableDmar *dmar;
- AcpiDmarHardwareUnit *drhd;
- AcpiDmarRootPortATS *atsr;
uint8_t dmar_flags = 0;
+ uint8_t rsvd10[10] = {};
+ /* Root complex IOAPIC uses one path only */
+ const size_t ioapic_scope_size = 6 /* device scope structure */ +
+ 2 /* 1 path entry */;
X86IOMMUState *iommu = x86_iommu_get_default();
- 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);
GArray *scope_blob = g_array_new(false, true, 1);
+ AcpiTable table = { .sig = "DMAR", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
+
/*
* A PCI bus walk, for each PCI host bridge.
* Insert scope for each PCI bridge and endpoint device which
@@ -2142,43 +2174,52 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id,
dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */
}
- dmar = acpi_data_push(table_data, sizeof(*dmar));
- dmar->host_address_width = intel_iommu->aw_bits - 1;
- dmar->flags = dmar_flags;
+ acpi_table_begin(&table, table_data);
+ /* Host Address Width */
+ build_append_int_noprefix(table_data, intel_iommu->aw_bits - 1, 1);
+ build_append_int_noprefix(table_data, dmar_flags, 1); /* Flags */
+ g_array_append_vals(table_data, rsvd10, sizeof(rsvd10)); /* Reserved */
- /* DMAR Remapping Hardware Unit Definition structure */
- drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size);
- drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT);
- drhd->length =
- cpu_to_le16(sizeof(*drhd) + ioapic_scope_size + scope_blob->len);
- drhd->flags = 0; /* Don't include all pci device */
- drhd->pci_segment = cpu_to_le16(0);
- drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR);
+ /* 8.3 DMAR Remapping Hardware Unit Definition structure */
+ build_append_int_noprefix(table_data, 0, 2); /* Type */
+ /* Length */
+ build_append_int_noprefix(table_data,
+ 16 + ioapic_scope_size + scope_blob->len, 2);
+ /* Flags */
+ build_append_int_noprefix(table_data, 0 /* Don't include all pci device */ ,
+ 1);
+ build_append_int_noprefix(table_data, 0 , 1); /* Reserved */
+ build_append_int_noprefix(table_data, 0 , 2); /* Segment Number */
+ /* Register Base Address */
+ build_append_int_noprefix(table_data, Q35_HOST_BRIDGE_IOMMU_ADDR , 8);
/* Scope definition for the root-complex IOAPIC. See VT-d spec
* 8.3.1 (version Oct. 2014 or later). */
- scope = &drhd->scope[0];
- scope->entry_type = 0x03; /* Type: 0x03 for IOAPIC */
- scope->length = ioapic_scope_size;
- scope->enumeration_id = ACPI_BUILD_IOAPIC_ID;
- scope->bus = Q35_PSEUDO_BUS_PLATFORM;
- scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC);
- scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC);
+ build_append_int_noprefix(table_data, 0x03 /* IOAPIC */, 1); /* Type */
+ build_append_int_noprefix(table_data, ioapic_scope_size, 1); /* Length */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ /* Enumeration ID */
+ build_append_int_noprefix(table_data, ACPI_BUILD_IOAPIC_ID, 1);
+ /* Start Bus Number */
+ build_append_int_noprefix(table_data, Q35_PSEUDO_BUS_PLATFORM, 1);
+ /* Path, {Device, Function} pair */
+ build_append_int_noprefix(table_data, PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC), 1);
+ build_append_int_noprefix(table_data, PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC), 1);
/* Add scope found above */
g_array_append_vals(table_data, scope_blob->data, scope_blob->len);
g_array_free(scope_blob, true);
if (iommu->dt_supported) {
- atsr = acpi_data_push(table_data, sizeof(*atsr));
- atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR);
- atsr->length = cpu_to_le16(sizeof(*atsr));
- atsr->flags = ACPI_DMAR_ATSR_ALL_PORTS;
- atsr->pci_segment = cpu_to_le16(0);
+ /* 8.5 Root Port ATS Capability Reporting Structure */
+ build_append_int_noprefix(table_data, 2, 2); /* Type */
+ build_append_int_noprefix(table_data, 8, 2); /* Length */
+ build_append_int_noprefix(table_data, 1 /* ALL_PORTS */, 1); /* Flags */
+ build_append_int_noprefix(table_data, 0, 1); /* Reserved */
+ build_append_int_noprefix(table_data, 0, 2); /* Segment Number */
}
- build_header(linker, table_data, (void *)(table_data->data + dmar_start),
- "DMAR", table_data->len - dmar_start, 1, oem_id, oem_table_id);
+ acpi_table_end(linker, &table);
}
/*
@@ -2192,10 +2233,10 @@ static void
build_waet(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
- int waet_start = table_data->len;
+ AcpiTable table = { .sig = "WAET", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
- /* WAET header */
- acpi_data_push(table_data, sizeof(AcpiTableHeader));
+ acpi_table_begin(&table, table_data);
/*
* Set "ACPI PM timer good" flag.
*
@@ -2204,9 +2245,7 @@ build_waet(GArray *table_data, BIOSLinker *linker, const char *oem_id,
* Which avoids costly VMExits caused by guest re-reading it unnecessarily.
*/
build_append_int_noprefix(table_data, 1 << 1 /* ACPI PM timer good */, 4);
-
- build_header(linker, table_data, (void *)(table_data->data + waet_start),
- "WAET", table_data->len - waet_start, 1, oem_id, oem_table_id);
+ acpi_table_end(linker, &table);
}
/*
@@ -2312,12 +2351,12 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
int ivhd_table_len = 24;
- int iommu_start = table_data->len;
AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());
GArray *ivhd_blob = g_array_new(false, true, 1);
+ AcpiTable table = { .sig = "IVRS", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
- /* IVRS header */
- acpi_data_push(table_data, sizeof(AcpiTableHeader));
+ acpi_table_begin(&table, table_data);
/* IVinfo - IO virtualization information common to all
* IOMMU units in a system
*/
@@ -2402,10 +2441,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
0x48, /* special device */
8);
}
-
- build_header(linker, table_data, (void *)(table_data->data + iommu_start),
- "IVRS", table_data->len - iommu_start, 1, oem_id,
- oem_table_id);
+ acpi_table_end(linker, &table);
}
typedef
diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c
index 1f5947f..4aaafbd 100644
--- a/hw/i386/acpi-common.c
+++ b/hw/i386/acpi-common.c
@@ -34,9 +34,13 @@
#include "acpi-common.h"
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
- const CPUArchIdList *apic_ids, GArray *entry)
+ const CPUArchIdList *apic_ids, GArray *entry,
+ bool force_enabled)
{
uint32_t apic_id = apic_ids->cpus[uid].arch_id;
+ /* Flags – Local APIC Flags */
+ uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ?
+ 1 /* Enabled */ : 0;
/* ACPI spec says that LAPIC entry for non present
* CPU may be omitted from MADT or it must be marked
@@ -45,82 +49,84 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
* should be put in MADT but kept disabled.
*/
if (apic_id < 255) {
- AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
-
- apic->type = ACPI_APIC_PROCESSOR;
- apic->length = sizeof(*apic);
- apic->processor_id = uid;
- apic->local_apic_id = apic_id;
- if (apic_ids->cpus[uid].cpu != NULL) {
- apic->flags = cpu_to_le32(1);
- } else {
- apic->flags = cpu_to_le32(0);
- }
+ /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */
+ build_append_int_noprefix(entry, 0, 1); /* Type */
+ build_append_int_noprefix(entry, 8, 1); /* Length */
+ build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */
+ build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */
+ build_append_int_noprefix(entry, flags, 4); /* Flags */
} else {
- AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic);
-
- apic->type = ACPI_APIC_LOCAL_X2APIC;
- apic->length = sizeof(*apic);
- apic->uid = cpu_to_le32(uid);
- apic->x2apic_id = cpu_to_le32(apic_id);
- if (apic_ids->cpus[uid].cpu != NULL) {
- apic->flags = cpu_to_le32(1);
- } else {
- apic->flags = cpu_to_le32(0);
- }
+ /* Rev 4.0, 5.2.12.12 Processor Local x2APIC Structure */
+ build_append_int_noprefix(entry, 9, 1); /* Type */
+ build_append_int_noprefix(entry, 16, 1); /* Length */
+ build_append_int_noprefix(entry, 0, 2); /* Reserved */
+ build_append_int_noprefix(entry, apic_id, 4); /* X2APIC ID */
+ build_append_int_noprefix(entry, flags, 4); /* Flags */
+ build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */
}
}
+static void build_ioapic(GArray *entry, uint8_t id, uint32_t addr, uint32_t irq)
+{
+ /* Rev 1.0b, 5.2.8.2 IO APIC */
+ build_append_int_noprefix(entry, 1, 1); /* Type */
+ build_append_int_noprefix(entry, 12, 1); /* Length */
+ build_append_int_noprefix(entry, id, 1); /* IO APIC ID */
+ build_append_int_noprefix(entry, 0, 1); /* Reserved */
+ build_append_int_noprefix(entry, addr, 4); /* IO APIC Address */
+ build_append_int_noprefix(entry, irq, 4); /* System Vector Base */
+}
+
+static void
+build_xrupt_override(GArray *entry, uint8_t src, uint32_t gsi, uint16_t flags)
+{
+ /* Rev 1.0b, 5.2.8.3.1 Interrupt Source Overrides */
+ build_append_int_noprefix(entry, 2, 1); /* Type */
+ build_append_int_noprefix(entry, 10, 1); /* Length */
+ build_append_int_noprefix(entry, 0, 1); /* Bus */
+ build_append_int_noprefix(entry, src, 1); /* Source */
+ /* Global System Interrupt Vector */
+ build_append_int_noprefix(entry, gsi, 4);
+ build_append_int_noprefix(entry, flags, 2); /* Flags */
+}
+
+/*
+ * ACPI spec, Revision 1.0b
+ * 5.2.8 Multiple APIC Description Table
+ */
void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
X86MachineState *x86ms, AcpiDeviceIf *adev,
const char *oem_id, const char *oem_table_id)
{
+ int i;
+ bool x2apic_mode = false;
MachineClass *mc = MACHINE_GET_CLASS(x86ms);
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms));
- int madt_start = table_data->len;
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev);
- bool x2apic_mode = false;
+ AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
- AcpiMultipleApicTable *madt;
- AcpiMadtIoApic *io_apic;
- AcpiMadtIntsrcovr *intsrcovr;
- int i;
-
- madt = acpi_data_push(table_data, sizeof *madt);
- madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS);
- madt->flags = cpu_to_le32(1);
+ acpi_table_begin(&table, table_data);
+ /* Local APIC Address */
+ build_append_int_noprefix(table_data, APIC_DEFAULT_ADDRESS, 4);
+ build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
for (i = 0; i < apic_ids->len; i++) {
- adevc->madt_cpu(adev, i, apic_ids, table_data);
+ adevc->madt_cpu(adev, i, apic_ids, table_data, false);
if (apic_ids->cpus[i].arch_id > 254) {
x2apic_mode = true;
}
}
- io_apic = acpi_data_push(table_data, sizeof *io_apic);
- io_apic->type = ACPI_APIC_IO;
- io_apic->length = sizeof(*io_apic);
- io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID;
- io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
- io_apic->interrupt = cpu_to_le32(0);
-
+ build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID, IO_APIC_DEFAULT_ADDRESS, 0);
if (x86ms->ioapic2) {
- AcpiMadtIoApic *io_apic2;
- io_apic2 = acpi_data_push(table_data, sizeof *io_apic);
- io_apic2->type = ACPI_APIC_IO;
- io_apic2->length = sizeof(*io_apic);
- io_apic2->io_apic_id = ACPI_BUILD_IOAPIC_ID + 1;
- io_apic2->address = cpu_to_le32(IO_APIC_SECONDARY_ADDRESS);
- io_apic2->interrupt = cpu_to_le32(IO_APIC_SECONDARY_IRQBASE);
+ build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID + 1,
+ IO_APIC_SECONDARY_ADDRESS, IO_APIC_SECONDARY_IRQBASE);
}
if (x86ms->apic_xrupt_override) {
- intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
- intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
- intsrcovr->length = sizeof(*intsrcovr);
- intsrcovr->source = 0;
- intsrcovr->gsi = cpu_to_le32(2);
- intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
+ build_xrupt_override(table_data, 0, 2,
+ 0 /* Flags: Conforms to the specifications of the bus */);
}
for (i = 1; i < 16; i++) {
@@ -128,36 +134,32 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
/* No need for a INT source override structure. */
continue;
}
- intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
- intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
- intsrcovr->length = sizeof(*intsrcovr);
- intsrcovr->source = i;
- intsrcovr->gsi = cpu_to_le32(i);
- intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
+ build_xrupt_override(table_data, i, i,
+ 0xd /* Flags: Active high, Level Triggered */);
}
if (x2apic_mode) {
- AcpiMadtLocalX2ApicNmi *local_nmi;
-
- local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
- local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI;
- local_nmi->length = sizeof(*local_nmi);
- local_nmi->uid = 0xFFFFFFFF; /* all processors */
- local_nmi->flags = cpu_to_le16(0);
- local_nmi->lint = 1; /* ACPI_LINT1 */
+ /* Rev 4.0, 5.2.12.13 Local x2APIC NMI Structure*/
+ build_append_int_noprefix(table_data, 0xA, 1); /* Type */
+ build_append_int_noprefix(table_data, 12, 1); /* Length */
+ build_append_int_noprefix(table_data, 0, 2); /* Flags */
+ /* ACPI Processor UID */
+ build_append_int_noprefix(table_data, 0xFFFFFFFF /* all processors */,
+ 4);
+ /* Local x2APIC LINT# */
+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1);
+ build_append_int_noprefix(table_data, 0, 3); /* Reserved */
} else {
- AcpiMadtLocalNmi *local_nmi;
-
- local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
- local_nmi->type = ACPI_APIC_LOCAL_NMI;
- local_nmi->length = sizeof(*local_nmi);
- local_nmi->processor_id = 0xff; /* all processors */
- local_nmi->flags = cpu_to_le16(0);
- local_nmi->lint = 1; /* ACPI_LINT1 */
+ /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */
+ build_append_int_noprefix(table_data, 4, 1); /* Type */
+ build_append_int_noprefix(table_data, 6, 1); /* Length */
+ /* ACPI Processor ID */
+ build_append_int_noprefix(table_data, 0xFF /* all processors */, 1);
+ build_append_int_noprefix(table_data, 0, 2); /* Flags */
+ /* Local APIC INTI# */
+ build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1);
}
- build_header(linker, table_data,
- (void *)(table_data->data + madt_start), "APIC",
- table_data->len - madt_start, 1, oem_id, oem_table_id);
+ acpi_table_end(linker, &table);
}
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index 1a0f77b..196d318 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -113,16 +113,16 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
Aml *dsdt, *sb_scope, *scope, *pkg;
bool ambiguous;
Object *isabus;
+ AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = x86ms->oem_id,
+ .oem_table_id = x86ms->oem_table_id };
isabus = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
assert(isabus);
assert(!ambiguous);
+ acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
- /* Reserve space for header */
- acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
-
sb_scope = aml_scope("_SB");
fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
isa_build_aml(ISA_BUS(isabus), sb_scope);
@@ -144,11 +144,10 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
aml_append(scope, aml_name_decl("_S5", pkg));
aml_append(dsdt, scope);
- /* copy AML table into ACPI tables blob and patch header there */
+ /* copy AML bytecode into ACPI tables blob */
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, x86ms->oem_id, x86ms->oem_table_id);
+
+ acpi_table_end(linker, &table);
free_aml_allocator();
}
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 2801dff..9242a0d 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1526,7 +1526,7 @@ static void amdvi_init(AMDVIState *s)
AMDVI_MAX_PH_ADDR | AMDVI_MAX_GVA_ADDR | AMDVI_MAX_VA_ADDR);
}
-static void amdvi_reset(DeviceState *dev)
+static void amdvi_sysbus_reset(DeviceState *dev)
{
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
@@ -1534,7 +1534,7 @@ static void amdvi_reset(DeviceState *dev)
amdvi_init(s);
}
-static void amdvi_realize(DeviceState *dev, Error **errp)
+static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
{
int ret = 0;
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
@@ -1585,27 +1585,27 @@ static void amdvi_realize(DeviceState *dev, Error **errp)
amdvi_init(s);
}
-static const VMStateDescription vmstate_amdvi = {
+static const VMStateDescription vmstate_amdvi_sysbus = {
.name = "amd-iommu",
.unmigratable = 1
};
-static void amdvi_instance_init(Object *klass)
+static void amdvi_sysbus_instance_init(Object *klass)
{
AMDVIState *s = AMD_IOMMU_DEVICE(klass);
object_initialize(&s->pci, sizeof(s->pci), TYPE_AMD_IOMMU_PCI);
}
-static void amdvi_class_init(ObjectClass *klass, void* data)
+static void amdvi_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
X86IOMMUClass *dc_class = X86_IOMMU_DEVICE_CLASS(klass);
- dc->reset = amdvi_reset;
- dc->vmsd = &vmstate_amdvi;
+ dc->reset = amdvi_sysbus_reset;
+ dc->vmsd = &vmstate_amdvi_sysbus;
dc->hotpluggable = false;
- dc_class->realize = amdvi_realize;
+ dc_class->realize = amdvi_sysbus_realize;
dc_class->int_remap = amdvi_int_remap;
/* Supported by the pc-q35-* machine types */
dc->user_creatable = true;
@@ -1613,18 +1613,27 @@ static void amdvi_class_init(ObjectClass *klass, void* data)
dc->desc = "AMD IOMMU (AMD-Vi) DMA Remapping device";
}
-static const TypeInfo amdvi = {
+static const TypeInfo amdvi_sysbus = {
.name = TYPE_AMD_IOMMU_DEVICE,
.parent = TYPE_X86_IOMMU_DEVICE,
.instance_size = sizeof(AMDVIState),
- .instance_init = amdvi_instance_init,
- .class_init = amdvi_class_init
+ .instance_init = amdvi_sysbus_instance_init,
+ .class_init = amdvi_sysbus_class_init
};
-static const TypeInfo amdviPCI = {
+static void amdvi_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->desc = "AMD IOMMU (AMD-Vi) DMA Remapping device";
+}
+
+static const TypeInfo amdvi_pci = {
.name = TYPE_AMD_IOMMU_PCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AMDVIPCIState),
+ .class_init = amdvi_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
@@ -1645,11 +1654,11 @@ static const TypeInfo amdvi_iommu_memory_region_info = {
.class_init = amdvi_iommu_memory_region_class_init,
};
-static void amdviPCI_register_types(void)
+static void amdvi_register_types(void)
{
- type_register_static(&amdviPCI);
- type_register_static(&amdvi);
+ type_register_static(&amdvi_pci);
+ type_register_static(&amdvi_sysbus);
type_register_static(&amdvi_iommu_memory_region_info);
}
-type_init(amdviPCI_register_types);
+type_init(amdvi_register_types);