aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-05-29 17:10:57 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-05-29 17:10:57 +0100
commit97af820f539efe80b87615a04f9de11ea585f725 (patch)
tree512a6ef6e94bbc643db77fba7666a065542acb73 /hw
parent2cc3bdbe2d3908f7a813d1c2d774cc2bf07746cd (diff)
parent3960c336ad96c2183549c8bf32bbff93ecda7ea4 (diff)
downloadqemu-97af820f539efe80b87615a04f9de11ea585f725.zip
qemu-97af820f539efe80b87615a04f9de11ea585f725.tar.gz
qemu-97af820f539efe80b87615a04f9de11ea585f725.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150529' into staging
target-arm: * Support ACPI for ARMv8 systems using the 'virt' board (and a UEFI boot image, typically) * avoid buffer overrun in some UNPREDICTABLE ldrd/strd cases * further work preparing for 64-bit EL2/EL3 support # gpg: Signature made Fri May 29 12:14:06 2015 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20150529: (39 commits) target-arm: Avoid buffer overrun on UNPREDICTABLE ldrd/strd hw/arm/virt: Enable dynamic generation of ACPI v5.1 tables ACPI: split CONFIG_ACPI into 4 pieces hw/arm/virt-acpi-build: Add PCIe controller in ACPI DSDT table hw/acpi/aml-build: Add Unicode macro hw/acpi/aml-build: Add aml_dword_io() term hw/acpi/aml-build: Add aml_create_dword_field() term hw/acpi/aml-build: Add aml_else() term hw/acpi/aml-build: Add aml_lnot() term hw/acpi/aml-build: Add aml_or() term hw/acpi/aml-build: Add ToUUID macro hw/acpi/aml-build: Make aml_buffer() definition consistent with the spec hw/arm/virt-acpi-build: Generate MCFG table hw/arm/virt-acpi-build: Generate RSDP table hw/arm/virt-acpi-build: Generate RSDT table hw/arm/virt-acpi-build: Generate GTDT table hw/arm/virt-acpi-build: Generate MADT table hw/arm/virt-acpi-build: Generate FADT table and update ACPI headers hw/arm/virt-acpi-build: Generation of DSDT table for virt devices hw/acpi/aml-build: Add aml_interrupt() term ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/Makefile.objs5
-rw-r--r--hw/acpi/aml-build.c231
-rw-r--r--hw/arm/Makefile.objs1
-rw-r--r--hw/arm/virt-acpi-build.c644
-rw-r--r--hw/arm/virt.c85
-rw-r--r--hw/i2c/Makefile.objs2
-rw-r--r--hw/i386/acpi-build.c82
7 files changed, 938 insertions, 112 deletions
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index b9fefa7..29d46d8 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -1,5 +1,6 @@
-common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o pcihp.o cpu_hotplug.o
-common-obj-$(CONFIG_ACPI) += memory_hotplug.o
+common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o ich9.o pcihp.o
+common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
+common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
common-obj-$(CONFIG_ACPI) += acpi_interface.o
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
common-obj-$(CONFIG_ACPI) += aml-build.o
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 77ce00b..323b7bc 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
+#include "qemu/bitops.h"
#include "hw/acpi/bios-linker-loader.h"
static GArray *build_alloc_array(void)
@@ -454,6 +455,16 @@ Aml *aml_and(Aml *arg1, Aml *arg2)
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */
+Aml *aml_or(Aml *arg1, Aml *arg2)
+{
+ Aml *var = aml_opcode(0x7D /* OrOp */);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
Aml *aml_notify(Aml *arg1, Aml *arg2)
{
@@ -505,6 +516,60 @@ Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
return var;
}
+/*
+ * ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
+ * (Type 1, Large Item Name 0x6)
+ */
+Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
+ AmlReadAndWrite read_and_write)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x86); /* Memory32Fixed Resource Descriptor */
+ build_append_byte(var->buf, 9); /* Length, bits[7:0] value = 9 */
+ build_append_byte(var->buf, 0); /* Length, bits[15:8] value = 0 */
+ build_append_byte(var->buf, read_and_write); /* Write status, 1 rw 0 ro */
+
+ /* Range base address */
+ build_append_byte(var->buf, extract32(addr, 0, 8)); /* bits[7:0] */
+ build_append_byte(var->buf, extract32(addr, 8, 8)); /* bits[15:8] */
+ build_append_byte(var->buf, extract32(addr, 16, 8)); /* bits[23:16] */
+ build_append_byte(var->buf, extract32(addr, 24, 8)); /* bits[31:24] */
+
+ /* Range length */
+ build_append_byte(var->buf, extract32(size, 0, 8)); /* bits[7:0] */
+ build_append_byte(var->buf, extract32(size, 8, 8)); /* bits[15:8] */
+ build_append_byte(var->buf, extract32(size, 16, 8)); /* bits[23:16] */
+ build_append_byte(var->buf, extract32(size, 24, 8)); /* bits[31:24] */
+ return var;
+}
+
+/*
+ * ACPI 5.0: 6.4.3.6 Extended Interrupt Descriptor
+ * Type 1, Large Item Name 0x9
+ */
+Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
+ AmlLevelAndEdge level_and_edge,
+ AmlActiveHighAndLow high_and_low, AmlShared shared,
+ uint32_t irq)
+{
+ Aml *var = aml_alloc();
+ uint8_t irq_flags = con_and_pro | (level_and_edge << 1)
+ | (high_and_low << 2) | (shared << 3);
+
+ build_append_byte(var->buf, 0x89); /* Extended irq descriptor */
+ build_append_byte(var->buf, 6); /* Length, bits[7:0] minimum value = 6 */
+ build_append_byte(var->buf, 0); /* Length, bits[15:8] minimum value = 0 */
+ build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */
+ build_append_byte(var->buf, 0x01); /* Interrupt table length = 1 */
+
+ /* Interrupt Number */
+ build_append_byte(var->buf, extract32(irq, 0, 8)); /* bits[7:0] */
+ build_append_byte(var->buf, extract32(irq, 8, 8)); /* bits[15:8] */
+ build_append_byte(var->buf, extract32(irq, 16, 8)); /* bits[23:16] */
+ build_append_byte(var->buf, extract32(irq, 24, 8)); /* bits[31:24] */
+ return var;
+}
+
/* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
uint8_t aln, uint8_t len)
@@ -542,6 +607,14 @@ Aml *aml_irq_no_flags(uint8_t irq)
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */
+Aml *aml_lnot(Aml *arg)
+{
+ Aml *var = aml_opcode(0x92 /* LNotOp */);
+ aml_append(var, arg);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
Aml *aml_equal(Aml *arg1, Aml *arg2)
{
@@ -559,6 +632,13 @@ Aml *aml_if(Aml *predicate)
return var;
}
+/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */
+Aml *aml_else(void)
+{
+ Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
Aml *aml_method(const char *name, int arg_count)
{
@@ -587,10 +667,22 @@ Aml *aml_resource_template(void)
return var;
}
-/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer */
-Aml *aml_buffer(void)
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer
+ * Pass byte_list as NULL to request uninitialized buffer to reserve space.
+ */
+Aml *aml_buffer(int buffer_size, uint8_t *byte_list)
{
+ int i;
Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
+
+ for (i = 0; i < buffer_size; i++) {
+ if (byte_list == NULL) {
+ build_append_byte(var->buf, 0x0);
+ } else {
+ build_append_byte(var->buf, byte_list[i]);
+ }
+ }
+
return var;
}
@@ -646,6 +738,17 @@ Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule)
return var;
}
+/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
+Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
+{
+ Aml *var = aml_alloc();
+ build_append_byte(var->buf, 0x8A); /* CreateDWordFieldOp */
+ aml_append(var, srcbuf);
+ aml_append(var, index);
+ build_append_namestring(var->buf, "%s", name);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
Aml *aml_string(const char *name_format, ...)
{
@@ -833,7 +936,7 @@ Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
uint16_t addr_trans, uint16_t len)
{
- return aml_word_as_desc(aml_bus_number_range, min_fixed, max_fixed, dec,
+ return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec,
addr_gran, addr_min, addr_max, addr_trans, len, 0);
}
@@ -850,7 +953,25 @@ Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
uint16_t len)
{
- return aml_word_as_desc(aml_io_range, min_fixed, max_fixed, dec,
+ return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
+ addr_gran, addr_min, addr_max, addr_trans, len,
+ isa_ranges);
+}
+
+/*
+ * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor
+ *
+ * More verbose description at:
+ * ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro)
+ */
+Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
+ AmlDecode dec, AmlISARanges isa_ranges,
+ uint32_t addr_gran, uint32_t addr_min,
+ uint32_t addr_max, uint32_t addr_trans,
+ uint32_t len)
+
+{
+ return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
addr_gran, addr_min, addr_max, addr_trans, len,
isa_ranges);
}
@@ -862,7 +983,7 @@ Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
* ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
*/
Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlCacheble cacheable,
+ AmlMaxFixed max_fixed, AmlCacheable cacheable,
AmlReadAndWrite read_and_write,
uint32_t addr_gran, uint32_t addr_min,
uint32_t addr_max, uint32_t addr_trans,
@@ -870,7 +991,7 @@ Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
{
uint8_t flags = read_and_write | (cacheable << 1);
- return aml_dword_as_desc(aml_memory_range, min_fixed, max_fixed,
+ return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
dec, addr_gran, addr_min, addr_max,
addr_trans, len, flags);
}
@@ -882,7 +1003,7 @@ Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
* ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
*/
Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
- AmlMaxFixed max_fixed, AmlCacheble cacheable,
+ AmlMaxFixed max_fixed, AmlCacheable cacheable,
AmlReadAndWrite read_and_write,
uint64_t addr_gran, uint64_t addr_min,
uint64_t addr_max, uint64_t addr_trans,
@@ -890,11 +1011,81 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
{
uint8_t flags = read_and_write | (cacheable << 1);
- return aml_qword_as_desc(aml_memory_range, min_fixed, max_fixed,
+ return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
dec, addr_gran, addr_min, addr_max,
addr_trans, len, flags);
}
+static uint8_t Hex2Byte(const char *src)
+{
+ int hi, lo;
+
+ hi = Hex2Digit(src[0]);
+ assert(hi >= 0);
+ assert(hi <= 15);
+
+ lo = Hex2Digit(src[1]);
+ assert(lo >= 0);
+ assert(lo <= 15);
+ return (hi << 4) | lo;
+}
+
+/*
+ * ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro)
+ * e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
+ * call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp");
+ */
+Aml *aml_touuid(const char *uuid)
+{
+ Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
+
+ assert(strlen(uuid) == 36);
+ assert(uuid[8] == '-');
+ assert(uuid[13] == '-');
+ assert(uuid[18] == '-');
+ assert(uuid[23] == '-');
+
+ build_append_byte(var->buf, Hex2Byte(uuid + 6)); /* dd - at offset 00 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 4)); /* cc - at offset 01 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 2)); /* bb - at offset 02 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 0)); /* aa - at offset 03 */
+
+ build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 9)); /* ee - at offset 05 */
+
+ build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */
+
+ build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */
+
+ build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */
+ build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */
+
+ return var;
+}
+
+/*
+ * ACPI 2.0b: 16.2.3.6.4.3 Unicode Macro (Convert Ascii String To Unicode)
+ */
+Aml *aml_unicode(const char *str)
+{
+ int i = 0;
+ Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
+
+ do {
+ build_append_byte(var->buf, str[i]);
+ build_append_byte(var->buf, 0);
+ i++;
+ } while (i <= strlen(str));
+
+ return var;
+}
+
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
@@ -951,3 +1142,27 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
g_array_free(tables->table_data, true);
g_array_free(tables->tcpalog, mfre);
}
+
+/* Build rsdt table */
+void
+build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
+{
+ AcpiRsdtDescriptorRev1 *rsdt;
+ size_t rsdt_len;
+ int i;
+ const int table_data_len = (sizeof(uint32_t) * table_offsets->len);
+
+ rsdt_len = sizeof(*rsdt) + table_data_len;
+ rsdt = acpi_data_push(table_data, rsdt_len);
+ memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len);
+ for (i = 0; i < table_offsets->len; ++i) {
+ /* rsdt->table_offset_entry to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker,
+ ACPI_BUILD_TABLE_FILE,
+ ACPI_BUILD_TABLE_FILE,
+ table_data, &rsdt->table_offset_entry[i],
+ sizeof(uint32_t));
+ }
+ build_header(linker, table_data,
+ (void *)rsdt, "RSDT", rsdt_len, 1);
+}
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index a75a182..4b09caf 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -3,6 +3,7 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
+obj-$(CONFIG_ACPI) += virt-acpi-build.o
obj-y += netduino2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
new file mode 100644
index 0000000..a9373cc
--- /dev/null
+++ b/hw/arm/virt-acpi-build.c
@@ -0,0 +1,644 @@
+/* Support for generating ACPI tables and passing them to Guests
+ *
+ * ARM virt ACPI generation
+ *
+ * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2013 Red Hat Inc
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
+ *
+ * Author: Shannon Zhao <zhaoshenglong@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "hw/arm/virt-acpi-build.h"
+#include "qemu/bitmap.h"
+#include "trace.h"
+#include "qom/cpu.h"
+#include "target-arm/cpu.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/acpi.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "hw/loader.h"
+#include "hw/hw.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/pci/pci.h"
+
+#define ARM_SPI_BASE 32
+
+typedef struct VirtAcpiCpuInfo {
+ DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT);
+} VirtAcpiCpuInfo;
+
+static void virt_acpi_get_cpu_info(VirtAcpiCpuInfo *cpuinfo)
+{
+ CPUState *cpu;
+
+ memset(cpuinfo->found_cpus, 0, sizeof cpuinfo->found_cpus);
+ CPU_FOREACH(cpu) {
+ set_bit(cpu->cpu_index, cpuinfo->found_cpus);
+ }
+}
+
+static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
+{
+ uint16_t i;
+
+ for (i = 0; i < smp_cpus; i++) {
+ Aml *dev = aml_device("C%03x", i);
+ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(i)));
+ aml_append(scope, dev);
+ }
+}
+
+static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
+ int uart_irq)
+{
+ Aml *dev = aml_device("COM0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(uart_memmap->base,
+ uart_memmap->size, AML_READ_WRITE));
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, uart_irq));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
+ int rtc_irq)
+{
+ Aml *dev = aml_device("RTC0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(rtc_memmap->base,
+ rtc_memmap->size, AML_READ_WRITE));
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, rtc_irq));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
+{
+ Aml *dev, *crs;
+ hwaddr base = flash_memmap->base;
+ hwaddr size = flash_memmap->size;
+
+ dev = aml_device("FLS0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+
+ dev = aml_device("FLS1");
+ aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(1)));
+ crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(base + size, size, AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+static void acpi_dsdt_add_virtio(Aml *scope,
+ const MemMapEntry *virtio_mmio_memmap,
+ int mmio_irq, int num)
+{
+ hwaddr base = virtio_mmio_memmap->base;
+ hwaddr size = virtio_mmio_memmap->size;
+ int irq = mmio_irq;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ Aml *dev = aml_device("VR%02u", i);
+ aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(i)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, irq + i));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+ base += size;
+ }
+}
+
+static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
+{
+ Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
+ int i, bus_no;
+ hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base;
+ hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size;
+ hwaddr base_pio = memmap[VIRT_PCIE_PIO].base;
+ hwaddr size_pio = memmap[VIRT_PCIE_PIO].size;
+ hwaddr base_ecam = memmap[VIRT_PCIE_ECAM].base;
+ hwaddr size_ecam = memmap[VIRT_PCIE_ECAM].size;
+ int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
+
+ Aml *dev = aml_device("%s", "PCI0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08")));
+ aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
+ aml_append(dev, aml_name_decl("_SEG", aml_int(0)));
+ aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
+ aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
+
+ /* Declare the PCI Routing Table. */
+ Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS);
+ for (bus_no = 0; bus_no < nr_pcie_buses; bus_no++) {
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ int gsi = (i + bus_no) % PCI_NUM_PINS;
+ Aml *pkg = aml_package(4);
+ aml_append(pkg, aml_int((bus_no << 16) | 0xFFFF));
+ aml_append(pkg, aml_int(i));
+ aml_append(pkg, aml_name("GSI%d", gsi));
+ aml_append(pkg, aml_int(0));
+ aml_append(rt_pkg, pkg);
+ }
+ }
+ aml_append(dev, aml_name_decl("_PRT", rt_pkg));
+
+ /* Create GSI link device */
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ Aml *dev_gsi = aml_device("GSI%d", i);
+ aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
+ aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0)));
+ crs = aml_resource_template();
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, irq + i));
+ aml_append(dev_gsi, aml_name_decl("_PRS", crs));
+ crs = aml_resource_template();
+ aml_append(crs,
+ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, irq + i));
+ aml_append(dev_gsi, aml_name_decl("_CRS", crs));
+ method = aml_method("_SRS", 1);
+ aml_append(dev_gsi, method);
+ aml_append(dev, dev_gsi);
+ }
+
+ method = aml_method("_CBA", 0);
+ aml_append(method, aml_return(aml_int(base_ecam)));
+ aml_append(dev, method);
+
+ method = aml_method("_CRS", 0);
+ Aml *rbuf = aml_resource_template();
+ aml_append(rbuf,
+ aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
+ 0x0000, 0x0000, nr_pcie_buses - 1, 0x0000,
+ nr_pcie_buses));
+ aml_append(rbuf,
+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, base_mmio,
+ base_mmio + size_mmio - 1, 0x0000, size_mmio));
+ aml_append(rbuf,
+ aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
+ AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio,
+ size_pio));
+
+ aml_append(method, aml_name_decl("RBUF", rbuf));
+ aml_append(method, aml_return(rbuf));
+ aml_append(dev, method);
+
+ /* Declare an _OSC (OS Control Handoff) method */
+ aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
+ aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
+ method = aml_method("_OSC", 4);
+ aml_append(method,
+ aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
+
+ /* PCI Firmware Specification 3.0
+ * 4.5.1. _OSC Interface for PCI Host Bridge Devices
+ * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
+ * identified by the Universal Unique IDentifier (UUID)
+ * 33DB4D5B-1FF7-401C-9657-7441C03DD766
+ */
+ UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766");
+ ifctx = aml_if(aml_equal(aml_arg(0), UUID));
+ aml_append(ifctx,
+ aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
+ aml_append(ifctx,
+ aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
+ aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
+ aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL")));
+ aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D)),
+ aml_name("CTRL")));
+
+ ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
+ aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08)),
+ aml_name("CDW1")));
+ aml_append(ifctx, ifctx1);
+
+ ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL"))));
+ aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10)),
+ aml_name("CDW1")));
+ aml_append(ifctx, ifctx1);
+
+ aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3")));
+ aml_append(ifctx, aml_return(aml_arg(3)));
+ aml_append(method, ifctx);
+
+ elsectx = aml_else();
+ aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4)),
+ aml_name("CDW1")));
+ aml_append(elsectx, aml_return(aml_arg(3)));
+ aml_append(method, elsectx);
+ aml_append(dev, method);
+
+ method = aml_method("_DSM", 4);
+
+ /* PCI Firmware Specification 3.0
+ * 4.6.1. _DSM for PCI Express Slot Information
+ * The UUID in _DSM in this context is
+ * {E5C937D0-3553-4D7A-9117-EA4D19C3434D}
+ */
+ UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
+ ifctx = aml_if(aml_equal(aml_arg(0), UUID));
+ ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0)));
+ uint8_t byte_list[1] = {1};
+ buf = aml_buffer(1, byte_list);
+ aml_append(ifctx1, aml_return(buf));
+ aml_append(ifctx, ifctx1);
+ aml_append(method, ifctx);
+
+ byte_list[0] = 0;
+ buf = aml_buffer(1, byte_list);
+ aml_append(method, aml_return(buf));
+ aml_append(dev, method);
+
+ Aml *dev_rp0 = aml_device("%s", "RP0");
+ aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, dev_rp0);
+ aml_append(scope, dev);
+}
+
+/* RSDP */
+static GArray *
+build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
+{
+ AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
+
+ bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
+ true /* fseg memory */);
+
+ memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
+ memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id));
+ rsdp->length = cpu_to_le32(sizeof(*rsdp));
+ rsdp->revision = 0x02;
+
+ /* Point to RSDT */
+ rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
+ /* Address to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
+ ACPI_BUILD_TABLE_FILE,
+ rsdp_table, &rsdp->rsdt_physical_address,
+ sizeof rsdp->rsdt_physical_address);
+ rsdp->checksum = 0;
+ /* Checksum to be filled by Guest linker */
+ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
+ rsdp, rsdp, sizeof *rsdp, &rsdp->checksum);
+
+ return rsdp_table;
+}
+
+static void
+build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
+{
+ AcpiTableMcfg *mcfg;
+ const MemMapEntry *memmap = guest_info->memmap;
+ int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
+
+ mcfg = acpi_data_push(table_data, len);
+ mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base);
+
+ /* Only a single allocation so no need to play with segments */
+ mcfg->allocation[0].pci_segment = cpu_to_le16(0);
+ mcfg->allocation[0].start_bus_number = 0;
+ mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
+ / PCIE_MMCFG_SIZE_MIN) - 1;
+
+ build_header(linker, table_data, (void *)mcfg, "MCFG", len, 5);
+}
+
+/* GTDT */
+static void
+build_gtdt(GArray *table_data, GArray *linker)
+{
+ int gtdt_start = table_data->len;
+ AcpiGenericTimerTable *gtdt;
+
+ gtdt = acpi_data_push(table_data, sizeof *gtdt);
+ /* The interrupt values are the same with the device tree when adding 16 */
+ gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16;
+ gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE;
+
+ gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16;
+ gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE;
+
+ gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16;
+ gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE;
+
+ gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16;
+ gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE;
+
+ build_header(linker, table_data,
+ (void *)(table_data->data + gtdt_start), "GTDT",
+ table_data->len - gtdt_start, 5);
+}
+
+/* MADT */
+static void
+build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info,
+ VirtAcpiCpuInfo *cpuinfo)
+{
+ int madt_start = table_data->len;
+ const MemMapEntry *memmap = guest_info->memmap;
+ AcpiMultipleApicTable *madt;
+ AcpiMadtGenericDistributor *gicd;
+ int i;
+
+ madt = acpi_data_push(table_data, sizeof *madt);
+
+ for (i = 0; i < guest_info->smp_cpus; i++) {
+ AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
+ sizeof *gicc);
+ gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
+ gicc->length = sizeof(*gicc);
+ gicc->base_address = memmap[VIRT_GIC_CPU].base;
+ gicc->cpu_interface_number = i;
+ gicc->arm_mpidr = i;
+ gicc->uid = i;
+ if (test_bit(i, cpuinfo->found_cpus)) {
+ gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
+ }
+ }
+
+ gicd = acpi_data_push(table_data, sizeof *gicd);
+ gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
+ gicd->length = sizeof(*gicd);
+ gicd->base_address = memmap[VIRT_GIC_DIST].base;
+
+ build_header(linker, table_data,
+ (void *)(table_data->data + madt_start), "APIC",
+ table_data->len - madt_start, 5);
+}
+
+/* FADT */
+static void
+build_fadt(GArray *table_data, GArray *linker, unsigned dsdt)
+{
+ AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
+
+ /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
+ fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
+ fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) |
+ (1 << ACPI_FADT_ARM_PSCI_USE_HVC));
+
+ /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
+ fadt->minor_revision = 0x1;
+
+ fadt->dsdt = cpu_to_le32(dsdt);
+ /* DSDT address to be filled by Guest linker */
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
+ ACPI_BUILD_TABLE_FILE,
+ table_data, &fadt->dsdt,
+ sizeof fadt->dsdt);
+
+ build_header(linker, table_data,
+ (void *)fadt, "FACP", sizeof(*fadt), 5);
+}
+
+/* DSDT */
+static void
+build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
+{
+ Aml *scope, *dsdt;
+ const MemMapEntry *memmap = guest_info->memmap;
+ const int *irqmap = guest_info->irqmap;
+
+ dsdt = init_aml_allocator();
+ /* Reserve space for header */
+ acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
+
+ scope = aml_scope("\\_SB");
+ acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
+ acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
+ (irqmap[VIRT_UART] + ARM_SPI_BASE));
+ acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
+ (irqmap[VIRT_RTC] + ARM_SPI_BASE));
+ acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
+ acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
+ (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
+ acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE));
+
+ aml_append(dsdt, scope);
+
+ /* 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, 5);
+ free_aml_allocator();
+}
+
+typedef
+struct AcpiBuildState {
+ /* Copy of table in RAM (for patching). */
+ MemoryRegion *table_mr;
+ MemoryRegion *rsdp_mr;
+ MemoryRegion *linker_mr;
+ /* Is table patched? */
+ bool patched;
+ VirtGuestInfo *guest_info;
+} AcpiBuildState;
+
+static
+void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
+{
+ GArray *table_offsets;
+ unsigned dsdt, rsdt;
+ VirtAcpiCpuInfo cpuinfo;
+ GArray *tables_blob = tables->table_data;
+
+ virt_acpi_get_cpu_info(&cpuinfo);
+
+ table_offsets = g_array_new(false, true /* clear */,
+ sizeof(uint32_t));
+
+ bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
+ 64, false /* high memory */);
+
+ /*
+ * The ACPI v5.1 tables for Hardware-reduced ACPI platform are:
+ * RSDP
+ * RSDT
+ * FADT
+ * GTDT
+ * MADT
+ * DSDT
+ */
+
+ /* DSDT is pointed to by FADT */
+ dsdt = tables_blob->len;
+ build_dsdt(tables_blob, tables->linker, guest_info);
+
+ /* FADT MADT GTDT pointed to by RSDT */
+ acpi_add_table(table_offsets, tables_blob);
+ build_fadt(tables_blob, tables->linker, dsdt);
+
+ acpi_add_table(table_offsets, tables_blob);
+ build_madt(tables_blob, tables->linker, guest_info, &cpuinfo);
+
+ acpi_add_table(table_offsets, tables_blob);
+ build_gtdt(tables_blob, tables->linker);
+
+ acpi_add_table(table_offsets, tables_blob);
+ build_mcfg(tables_blob, tables->linker, guest_info);
+
+ /* RSDT is pointed to by RSDP */
+ rsdt = tables_blob->len;
+ build_rsdt(tables_blob, tables->linker, table_offsets);
+
+ /* RSDP is in FSEG memory, so allocate it separately */
+ build_rsdp(tables->rsdp, tables->linker, rsdt);
+
+ /* Cleanup memory that's no longer used. */
+ g_array_free(table_offsets, true);
+}
+
+static void acpi_ram_update(MemoryRegion *mr, GArray *data)
+{
+ uint32_t size = acpi_data_len(data);
+
+ /* Make sure RAM size is correct - in case it got changed
+ * e.g. by migration */
+ memory_region_ram_resize(mr, size, &error_abort);
+
+ memcpy(memory_region_get_ram_ptr(mr), data->data, size);
+ memory_region_set_dirty(mr, 0, size);
+}
+
+static void virt_acpi_build_update(void *build_opaque, uint32_t offset)
+{
+ AcpiBuildState *build_state = build_opaque;
+ AcpiBuildTables tables;
+
+ /* No state to update or already patched? Nothing to do. */
+ if (!build_state || build_state->patched) {
+ return;
+ }
+ build_state->patched = true;
+
+ acpi_build_tables_init(&tables);
+
+ virt_acpi_build(build_state->guest_info, &tables);
+
+ acpi_ram_update(build_state->table_mr, tables.table_data);
+ acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
+ acpi_ram_update(build_state->linker_mr, tables.linker);
+
+
+ acpi_build_tables_cleanup(&tables, true);
+}
+
+static void virt_acpi_build_reset(void *build_opaque)
+{
+ AcpiBuildState *build_state = build_opaque;
+ build_state->patched = false;
+}
+
+static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
+ GArray *blob, const char *name,
+ uint64_t max_size)
+{
+ return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
+ name, virt_acpi_build_update, build_state);
+}
+
+static const VMStateDescription vmstate_virt_acpi_build = {
+ .name = "virt_acpi_build",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(patched, AcpiBuildState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+void virt_acpi_setup(VirtGuestInfo *guest_info)
+{
+ AcpiBuildTables tables;
+ AcpiBuildState *build_state;
+
+ if (!guest_info->fw_cfg) {
+ trace_virt_acpi_setup();
+ return;
+ }
+
+ if (!acpi_enabled) {
+ trace_virt_acpi_setup();
+ return;
+ }
+
+ build_state = g_malloc0(sizeof *build_state);
+ build_state->guest_info = guest_info;
+
+ acpi_build_tables_init(&tables);
+ virt_acpi_build(build_state->guest_info, &tables);
+
+ /* Now expose it all to Guest */
+ build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
+ ACPI_BUILD_TABLE_FILE,
+ ACPI_BUILD_TABLE_MAX_SIZE);
+ assert(build_state->table_mr != NULL);
+
+ build_state->linker_mr =
+ acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
+
+ fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
+ tables.tcpalog->data, acpi_data_len(tables.tcpalog));
+
+ build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
+ ACPI_BUILD_RSDP_FILE, 0);
+
+ qemu_register_reset(virt_acpi_build_reset, build_state);
+ virt_acpi_build_reset(build_state);
+ vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
+
+ /* Cleanup tables but don't free the memory: we track it
+ * in build_state.
+ */
+ acpi_build_tables_cleanup(&tables, false);
+}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a7f9a10..05db8cb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -31,6 +31,7 @@
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
+#include "hw/arm/virt.h"
#include "hw/devices.h"
#include "net/net.h"
#include "sysemu/block-backend.h"
@@ -43,8 +44,7 @@
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "hw/pci-host/gpex.h"
-
-#define NUM_VIRTIO_TRANSPORTS 32
+#include "hw/arm/virt-acpi-build.h"
/* Number of external interrupt lines to configure the GIC with */
#define NUM_IRQS 128
@@ -60,24 +60,6 @@
#define GIC_FDT_IRQ_PPI_CPU_START 8
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
-enum {
- VIRT_FLASH,
- VIRT_MEM,
- VIRT_CPUPERIPHS,
- VIRT_GIC_DIST,
- VIRT_GIC_CPU,
- VIRT_UART,
- VIRT_MMIO,
- VIRT_RTC,
- VIRT_FW_CFG,
- VIRT_PCIE,
-};
-
-typedef struct MemMapEntry {
- hwaddr base;
- hwaddr size;
-} MemMapEntry;
-
typedef struct VirtBoardInfo {
struct arm_boot_info bootinfo;
const char *cpu_model;
@@ -131,14 +113,9 @@ static const MemMapEntry a15memmap[] = {
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
- /*
- * PCIE verbose map:
- *
- * MMIO window { 0x10000000, 0x2eff0000 },
- * PIO window { 0x3eff0000, 0x00010000 },
- * ECAM { 0x3f000000, 0x01000000 },
- */
- [VIRT_PCIE] = { 0x10000000, 0x30000000 },
+ [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
+ [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
+ [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
};
@@ -289,10 +266,10 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
"arm,armv7-timer");
}
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
- GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, 11, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, 10, irqflags);
+ GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags,
+ GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags,
+ GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags,
+ GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags);
}
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
@@ -644,16 +621,14 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
uint32_t gic_phandle)
{
- hwaddr base = vbi->memmap[VIRT_PCIE].base;
- hwaddr size = vbi->memmap[VIRT_PCIE].size;
- hwaddr end = base + size;
- hwaddr size_mmio;
- hwaddr size_ioport = 64 * 1024;
- int nr_pcie_buses = 16;
- hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN * nr_pcie_buses;
- hwaddr base_mmio = base;
- hwaddr base_ioport;
- hwaddr base_ecam;
+ hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
+ hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
+ hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base;
+ hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size;
+ hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base;
+ hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size;
+ hwaddr base = base_mmio;
+ int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
int irq = vbi->irqmap[VIRT_PCIE];
MemoryRegion *mmio_alias;
MemoryRegion *mmio_reg;
@@ -663,10 +638,6 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
char *nodename;
int i;
- base_ecam = QEMU_ALIGN_DOWN(end - size_ecam, size_ecam);
- base_ioport = QEMU_ALIGN_DOWN(base_ecam - size_ioport, size_ioport);
- size_mmio = base_ioport - base;
-
dev = qdev_create(NULL, TYPE_GPEX_HOST);
qdev_init_nofail(dev);
@@ -689,7 +660,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
/* Map IO port space */
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
for (i = 0; i < GPEX_NUM_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
@@ -709,7 +680,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
2, base_ecam, 2, size_ecam);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, base_ioport, 2, size_ioport,
+ 2, base_pio, 2, size_pio,
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
2, base_mmio, 2, size_mmio);
@@ -727,6 +698,14 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
return board->fdt;
}
+static
+void virt_guest_info_machine_done(Notifier *notifier, void *data)
+{
+ VirtGuestInfoState *guest_info_state = container_of(notifier,
+ VirtGuestInfoState, machine_done);
+ virt_acpi_setup(&guest_info_state->info);
+}
+
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
@@ -736,6 +715,8 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *ram = g_new(MemoryRegion, 1);
const char *cpu_model = machine->cpu_model;
VirtBoardInfo *vbi;
+ VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
+ VirtGuestInfo *guest_info = &guest_info_state->info;
uint32_t gic_phandle;
char **cpustr;
@@ -828,6 +809,14 @@ static void machvirt_init(MachineState *machine)
create_virtio_devices(vbi, pic);
create_fw_cfg(vbi);
+ rom_set_fw(fw_cfg_find());
+
+ guest_info->smp_cpus = smp_cpus;
+ guest_info->fw_cfg = fw_cfg_find();
+ guest_info->memmap = vbi->memmap;
+ guest_info->irqmap = vbi->irqmap;
+ guest_info_state->machine_done.notify = virt_guest_info_machine_done;
+ qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
vbi->bootinfo.ram_size = machine->ram_size;
vbi->bootinfo.kernel_filename = machine->kernel_filename;
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 648278e..0f13060 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-y += core.o smbus.o smbus_eeprom.o
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
-common-obj-$(CONFIG_ACPI) += smbus_ich9.o
+common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
common-obj-$(CONFIG_APM) += pm_smbus.o
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 73259e7..3d19de6 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -620,31 +620,31 @@ build_ssdt(GArray *table_data, GArray *linker,
/* build PCI0._CRS */
crs = aml_resource_template();
aml_append(crs,
- aml_word_bus_number(aml_min_fixed, aml_max_fixed, aml_pos_decode,
+ aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
0x0000, 0x0000, 0x00FF, 0x0000, 0x0100));
- aml_append(crs, aml_io(aml_decode16, 0x0CF8, 0x0CF8, 0x01, 0x08));
+ aml_append(crs, aml_io(AML_DECODE16, 0x0CF8, 0x0CF8, 0x01, 0x08));
aml_append(crs,
- aml_word_io(aml_min_fixed, aml_max_fixed,
- aml_pos_decode, aml_entire_range,
+ aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_POS_DECODE, AML_ENTIRE_RANGE,
0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
aml_append(crs,
- aml_word_io(aml_min_fixed, aml_max_fixed,
- aml_pos_decode, aml_entire_range,
+ aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_POS_DECODE, AML_ENTIRE_RANGE,
0x0000, 0x0D00, 0xFFFF, 0x0000, 0xF300));
aml_append(crs,
- aml_dword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
- aml_cacheable, aml_ReadWrite,
+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_CACHEABLE, AML_READ_WRITE,
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
aml_append(crs,
- aml_dword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
- aml_non_cacheable, aml_ReadWrite,
+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_NON_CACHEABLE, AML_READ_WRITE,
0, pci->w32.begin, pci->w32.end - 1, 0,
pci->w32.end - pci->w32.begin));
if (pci->w64.begin) {
aml_append(crs,
- aml_qword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
- aml_cacheable, aml_ReadWrite,
+ aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_CACHEABLE, AML_READ_WRITE,
0, pci->w64.begin, pci->w64.end - 1, 0,
pci->w64.end - pci->w64.begin));
}
@@ -658,7 +658,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
+ aml_io(AML_DECODE16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
@@ -673,7 +673,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
+ aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
pm->pcihp_io_len)
);
aml_append(dev, aml_name_decl("_CRS", crs));
@@ -720,7 +720,7 @@ build_ssdt(GArray *table_data, GArray *linker,
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, misc->applesmc_io_base, misc->applesmc_io_base,
+ aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base,
0x01, APPLESMC_MAX_DATA_LENGTH)
);
aml_append(crs, aml_irq_no_flags(6));
@@ -738,13 +738,13 @@ build_ssdt(GArray *table_data, GArray *linker,
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
+ aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
);
aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(dev, aml_operation_region("PEOR", aml_system_io,
+ aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
misc->pvpanic_port, 1));
- field = aml_field("PEOR", aml_byte_acc, aml_preserve);
+ field = aml_field("PEOR", AML_BYTE_ACC, AML_PRESERVE);
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
@@ -773,15 +773,15 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1,
+ aml_io(AML_DECODE16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1,
pm->cpu_hp_io_len)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(sb_scope, dev);
/* declare CPU hotplug MMIO region and PRS field to access it */
aml_append(sb_scope, aml_operation_region(
- "PRST", aml_system_io, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
- field = aml_field("PRST", aml_byte_acc, aml_preserve);
+ "PRST", AML_SYSTEM_IO, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
+ field = aml_field("PRST", AML_BYTE_ACC, AML_PRESERVE);
aml_append(field, aml_named_field("PRS", 256));
aml_append(sb_scope, field);
@@ -845,18 +845,18 @@ build_ssdt(GArray *table_data, GArray *linker,
crs = aml_resource_template();
aml_append(crs,
- aml_io(aml_decode16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0,
+ aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0,
pm->mem_hp_io_len)
);
aml_append(scope, aml_name_decl("_CRS", crs));
aml_append(scope, aml_operation_region(
- stringify(MEMORY_HOTPLUG_IO_REGION), aml_system_io,
+ stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO,
pm->mem_hp_io_base, pm->mem_hp_io_len)
);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
- aml_preserve);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC,
+ AML_PRESERVE);
aml_append(field, /* read only */
aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32));
aml_append(field, /* read only */
@@ -869,8 +869,8 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32));
aml_append(scope, field);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc,
- aml_write_as_zeros);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC,
+ AML_WRITE_AS_ZEROS);
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
aml_append(field, /* 1 if enabled, read only */
aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1));
@@ -885,8 +885,8 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_named_field(stringify(MEMORY_SLOT_EJECT), 1));
aml_append(scope, field);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
- aml_preserve);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC,
+ AML_PRESERVE);
aml_append(field, /* DIMM selector, write only */
aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32));
aml_append(field, /* _OST event code, write only */
@@ -1208,30 +1208,6 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc)
misc->dsdt_size, 1);
}
-/* Build final rsdt table */
-static void
-build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
-{
- AcpiRsdtDescriptorRev1 *rsdt;
- size_t rsdt_len;
- int i;
-
- rsdt_len = sizeof(*rsdt) + sizeof(uint32_t) * table_offsets->len;
- rsdt = acpi_data_push(table_data, rsdt_len);
- memcpy(rsdt->table_offset_entry, table_offsets->data,
- sizeof(uint32_t) * table_offsets->len);
- for (i = 0; i < table_offsets->len; ++i) {
- /* rsdt->table_offset_entry to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_FILE,
- table_data, &rsdt->table_offset_entry[i],
- sizeof(uint32_t));
- }
- build_header(linker, table_data,
- (void *)rsdt, "RSDT", rsdt_len, 1);
-}
-
static GArray *
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
{