diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-05-29 17:10:57 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-05-29 17:10:57 +0100 |
commit | 97af820f539efe80b87615a04f9de11ea585f725 (patch) | |
tree | 512a6ef6e94bbc643db77fba7666a065542acb73 /hw | |
parent | 2cc3bdbe2d3908f7a813d1c2d774cc2bf07746cd (diff) | |
parent | 3960c336ad96c2183549c8bf32bbff93ecda7ea4 (diff) | |
download | qemu-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.objs | 5 | ||||
-rw-r--r-- | hw/acpi/aml-build.c | 231 | ||||
-rw-r--r-- | hw/arm/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/arm/virt-acpi-build.c | 644 | ||||
-rw-r--r-- | hw/arm/virt.c | 85 | ||||
-rw-r--r-- | hw/i2c/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/i386/acpi-build.c | 82 |
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) { |