From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38512) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UwGvt-0003F5-Dx for qemu-devel@nongnu.org; Mon, 08 Jul 2013 15:17:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UwGvm-0007m1-BY for qemu-devel@nongnu.org; Mon, 08 Jul 2013 15:17:09 -0400 Received: from e38.co.us.ibm.com ([32.97.110.159]:54661) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UwGvl-0007lb-HZ for qemu-devel@nongnu.org; Mon, 08 Jul 2013 15:17:02 -0400 Received: from /spool/local by e38.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 8 Jul 2013 13:16:39 -0600 Received: from d03relay04.boulder.ibm.com (d03relay04.boulder.ibm.com [9.17.195.106]) by d03dlp01.boulder.ibm.com (Postfix) with ESMTP id AB7CE1FF003C for ; Mon, 8 Jul 2013 13:11:17 -0600 (MDT) Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by d03relay04.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r68JGVPe105906 for ; Mon, 8 Jul 2013 13:16:31 -0600 Received: from d03av05.boulder.ibm.com (loopback [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r68JGVDZ032477 for ; Mon, 8 Jul 2013 13:16:31 -0600 From: Anthony Liguori In-Reply-To: <1373307914-18543-5-git-send-email-mst@redhat.com> References: <1373307914-18543-1-git-send-email-mst@redhat.com> <1373307914-18543-5-git-send-email-mst@redhat.com> Date: Mon, 08 Jul 2013 14:16:13 -0500 Message-ID: <87d2qs3ls2.fsf@codemonkey.ws> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Subject: Re: [Qemu-devel] [SeaBIOS] [PATCH v2 4/4] i386: ACPI table generation code from seabios List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "Michael S. Tsirkin" , qemu-devel@nongnu.org Cc: seabios@seabios.org "Michael S. Tsirkin" writes: > This adds C code for generating ACPI tables at runtime, > imported from seabios git tree > commit 51684b7ced75fb76776e8ee84833fcfb6ecf12dd > > Although ACPI tables come from a system BIOS on real hw, > it makes sense that the ACPI tables are coupled with the > virtual machine, since they have to abstract the x86 machine to > the OS's. > > This is widely desired as a way to avoid the churn > and proliferation of QEMU-specific interfaces > associated with ACPI tables in bios code. > > Notes: > The code structure was intentionally kept as close > to the seabios original as possible, to simplify > comparison and making sure we didn't lose anything > in translation. > > Minor code duplication results, to help ensure there are no functional > regressions, I think it's better to merge it like this and do more code > changes in follow-up patches. > > Cross-version compatibility concerns have been addressed: > ACPI tables are exposed to guest as FW_CFG entries. > When running with -M 1.5 and older, this patch disables ACPI > table generation, and doesn't expose ACPI > tables to guest. > > As table content is likely to change over time, > the following measures are taken to simplify > cross-version migration: > - All tables besides the RSDP are packed in a single FW CFG entry. > This entry size is currently 23K. We round it up to 64K > to avoid too much churn there. > - Tables are placed in special ROM blob (not mapped into guest memory) > which is automatically migrated together with the guest, same > as BIOS code. This seems reasonable. > > This patch reuses some code from SeaBIOS, which was originally under > LGPLv2 and then relicensed to GPLv3 or LGPLv3, in QEMU under GPLv2+. This > relicensing has been acked by all contributors that had contributed to the > code since the v2->v3 relicense. ACKs approving the v2+ relicensing are > listed below. The list might include ACKs from people not holding > copyright on any parts of the reused code, but it's better to err on the > side of caution and include them. Thank you for collecting the Acks. > > Affected SeaBIOS files (GPLv2+ license headers added) > : > > src/acpi-dsdt-cpu-hotplug.dsl > src/acpi-dsdt-dbug.dsl > src/acpi-dsdt-hpet.dsl > src/acpi-dsdt-isa.dsl > src/acpi-dsdt-pci-crs.dsl > src/acpi.c > src/acpi.h > src/ssdt-misc.dsl > src/ssdt-pcihp.dsl > src/ssdt-proc.dsl > tools/acpi_extract.py > tools/acpi_extract_preprocess.py > > Each one of the listed people agreed to the following: > >> If you allow the use of your contribution in QEMU under the >> terms of GPLv2 or later as proposed by this patch, >> please respond to this mail including the line: >> >> Acked-by: Name > > Acked-by: Gerd Hoffmann > Acked-by: Jan Kiszka > Acked-by: Jason Baron > Acked-by: David Woodhouse > Acked-by: Gleb Natapov > Acked-by: Marcelo Tosatti > Acked-by: Dave Frodin > Acked-by: Paolo Bonzini > Acked-by: Kevin O'Connor > Acked-by: Laszlo Ersek > Acked-by: Kenji Kaneshige > Acked-by: Isaku Yamahata > Acked-by: Magnus Christensson > Acked-by: Hu Tao > Acked-by: Eduardo Habkost > > Signed-off-by: Michael S. Tsirkin > --- > hw/i386/Makefile.objs | 2 + > hw/i386/acpi-build.c | 723 +++++++++++++++++++++++++++++++++++++++++++ > hw/i386/acpi-defs.h | 327 +++++++++++++++++++ > hw/i386/pc.c | 2 + > hw/i386/pc_piix.c | 3 + > hw/i386/pc_q35.c | 3 + > hw/i386/ssdt-misc.dsl | 46 +++ > include/hw/i386/acpi-build.h | 9 + > include/hw/i386/pc.h | 1 + > 9 files changed, 1116 insertions(+) > create mode 100644 hw/i386/acpi-build.c > create mode 100644 hw/i386/acpi-defs.h > create mode 100644 include/hw/i386/acpi-build.h > > diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs > index e783050..2ab2572 100644 > --- a/hw/i386/Makefile.objs > +++ b/hw/i386/Makefile.objs > @@ -4,7 +4,9 @@ obj-y += pc.o pc_piix.o pc_q35.o > obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o > > obj-y += kvmvapic.o > +obj-y += acpi-build.o > obj-y += bios-linker-loader.o > +hw/i386/acpi-build.o: hw/i386/acpi-build.c hw/i386/acpi-dsdt.hex hw/i386/ssdt-proc.hex hw/i386/ssdt-pcihp.hex hw/i386/ssdt-misc.hex hw/i386/q35-acpi-dsdt.hex > hw/i386/pc_piix.o: hw/i386/pc_piix.c hw/i386/acpi-dsdt.hex > hw/i386/pc_q35.o: hw/i386/pc_q35.c hw/i386/q35-acpi-dsdt.hex > > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > new file mode 100644 > index 0000000..bc44f95 > --- /dev/null > +++ b/hw/i386/acpi-build.c > @@ -0,0 +1,723 @@ > +/* Support for generating ACPI tables and passing them to Guests > + * > + * Copyright (C) 2008-2010 Kevin O'Connor > + * Copyright (C) 2006 Fabrice Bellard > + * Copyright (C) 2013 Red Hat Inc > + * > + * Author: Michael S. Tsirkin > + * > + * 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 . > + */ > + > +#include "hw/i386/acpi-build.h" > +#include > +#include > +#include "qemu/bitmap.h" > +#include "qemu/range.h" > +#include "hw/pci/pci.h" > +#include "qom/cpu.h" > +#include "hw/i386/pc.h" > +#include "target-i386/cpu.h" > +#include "hw/timer/hpet.h" > +#include "hw/i386/acpi-defs.h" > +#include "hw/acpi/acpi.h" > +#include "hw/nvram/fw_cfg.h" > +#include "hw/i386/bios-linker-loader.h" > +#include "hw/loader.h" > + > +#define ACPI_BUILD_APPNAME "Bochs" > +#define ACPI_BUILD_APPNAME6 "BOCHS " > +#define ACPI_BUILD_APPNAME4 "BXPC" > + > +#define ACPI_BUILD_DPRINTF(level, fmt, ...) do {} while(0) > + > +#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables" > +#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp" > + > +static void > +build_header(GArray *linker, GArray *table_data, > + AcpiTableHeader *h, uint32_t sig, int len, uint8_t rev) > +{ > + h->signature = cpu_to_le32(sig); > + h->length = cpu_to_le32(len); > + h->revision = rev; > + memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); > + memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); > + memcpy(h->oem_table_id + 4, (void*)&sig, 4); > + h->oem_revision = cpu_to_le32(1); > + memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); > + h->asl_compiler_revision = cpu_to_le32(1); > + h->checksum = 0; > + /* Checksum to be filled in by Guest linker */ > + bios_linker_add_checksum(linker, ACPI_BUILD_TABLE_FILE, > + table_data->data, h, len, &h->checksum); > +} > + > +#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */ > +#define ACPI_PORT_PM_BASE 0xb000 > + > +static inline void *acpi_data_push(GArray *table_data, unsigned size) > +{ > + unsigned off = table_data->len; > + g_array_set_size(table_data, off + size); > + return table_data->data + off; > +} > + > +static unsigned acpi_data_len(GArray *table) > +{ > + return table->len * g_array_get_element_size(table); > +} > + > +static inline void acpi_add_table(GArray *table_offsets, GArray *table_data) > +{ > + uint32_t offset = cpu_to_le32(table_data->len); > + g_array_append_val(table_offsets, offset); > +} > + > +/* FACS */ > +static void > +build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) > +{ > + AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs); > + facs->signature = cpu_to_le32(ACPI_FACS_SIGNATURE); > + facs->length = cpu_to_le32(sizeof(*facs)); > +} > + > +/* Load chipset information into FADT */ > +static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, PcGuestInfo *guest_info) > +{ > + fadt->model = 1; > + fadt->reserved1 = 0; > + fadt->sci_int = cpu_to_le16(guest_info->sci_int); > + fadt->smi_cmd = cpu_to_le32(ACPI_PORT_SMI_CMD); > + fadt->acpi_enable = guest_info->acpi_enable_cmd; > + fadt->acpi_disable = guest_info->acpi_disable_cmd; > + fadt->pm1a_evt_blk = cpu_to_le32(ACPI_PORT_PM_BASE); > + fadt->pm1a_cnt_blk = cpu_to_le32(ACPI_PORT_PM_BASE + 0x04); > + fadt->pm_tmr_blk = cpu_to_le32(ACPI_PORT_PM_BASE + 0x08); > + fadt->gpe0_blk = cpu_to_le32(guest_info->gpe0_blk); > + fadt->pm1_evt_len = 4; > + fadt->pm1_cnt_len = 2; > + fadt->pm_tmr_len = 4; > + fadt->gpe0_blk_len = guest_info->gpe0_blk_len; > + fadt->plvl2_lat = cpu_to_le16(0xfff); /* C2 state not supported */ > + fadt->plvl3_lat = cpu_to_le16(0xfff); /* C3 state not supported */ > + fadt->flags = cpu_to_le32((1 << ACPI_FADT_F_WBINVD) | > + (1 << ACPI_FADT_F_PROC_C1) | > + (1 << ACPI_FADT_F_SLP_BUTTON) | > + (1 << ACPI_FADT_F_RTC_S4)); > + if (guest_info->fix_rtc) { > + fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FIX_RTC); > + } > + if (guest_info->platform_timer) { > + fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK); > + } > +} > + > + > +/* FADT */ > +static void > +build_fadt(GArray *table_data, GArray *linker, PcGuestInfo *guest_info, > + unsigned facs, unsigned dsdt) > +{ > + AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); > + > + fadt->firmware_ctrl = cpu_to_le32(facs); > + /* FACS address to be filled by Guest linker */ > + bios_linker_add_pointer(linker, ACPI_BUILD_TABLE_FILE, ACPI_BUILD_TABLE_FILE, > + table_data, &fadt->firmware_ctrl, > + sizeof fadt->firmware_ctrl); > + > + fadt->dsdt = cpu_to_le32(dsdt); > + /* DSDT address to be filled by Guest linker */ > + bios_linker_add_pointer(linker, ACPI_BUILD_TABLE_FILE, ACPI_BUILD_TABLE_FILE, > + table_data, &fadt->dsdt, > + sizeof fadt->dsdt); > + > + fadt_setup(fadt, guest_info); > + > + build_header(linker, table_data, > + (void*)fadt, ACPI_FACP_SIGNATURE, sizeof(*fadt), 1); > +} > + > +static void > +build_madt(GArray *table_data, GArray *linker, FWCfgState *fw_cfg, PcGuestInfo *guest_info) > +{ > + int madt_size; > + > + AcpiMultipleApicTable *madt; > + AcpiMadtProcessorApic *apic; > + AcpiMadtIoApic *io_apic; > + AcpiMadtIntsrcovr *intsrcovr; > + AcpiMadtLocalNmi *local_nmi; > + > + madt_size = (sizeof(AcpiMultipleApicTable) > + + sizeof(AcpiMadtProcessorApic) * guest_info->apic_id_limit > + + sizeof(AcpiMadtIoApic) > + + sizeof(AcpiMadtIntsrcovr) * 16 > + + sizeof(AcpiMadtLocalNmi)); > + madt = acpi_data_push(table_data, madt_size); > + madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS); > + madt->flags = cpu_to_le32(1); > + apic = (void*)&madt[1]; > + int i; Variables belong at top of functions. The fancy casting math is dangerous too. You're overrunning buffers and will likely confuse static checks. Best to use a void * pointer and do the assignments based on offsets. > + for (i=0; i < guest_info->apic_id_limit; i++) { > + apic->type = ACPI_APIC_PROCESSOR; > + apic->length = sizeof(*apic); > + apic->processor_id = i; > + apic->local_apic_id = i; > + if (test_bit(i, guest_info->found_cpus)) > + apic->flags = cpu_to_le32(1); > + else > + apic->flags = cpu_to_le32(0); > + apic++; > + } > + io_apic = (void*)apic; > + io_apic->type = ACPI_APIC_IO; > + io_apic->length = sizeof(*io_apic); > +#define ACPI_BUILD_IOAPIC_ID 0x0 > + io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID; > + io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); > + io_apic->interrupt = cpu_to_le32(0); > + > + intsrcovr = (void*)&io_apic[1]; > + if (guest_info->apic_xrupt_override) { > + memset(intsrcovr, 0, sizeof(*intsrcovr)); > + intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; > + intsrcovr->length = sizeof(*intsrcovr); > + intsrcovr->source = 0; > + intsrcovr->gsi = cpu_to_le32(2); > + intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */ > + intsrcovr++; > + } > + for (i = 1; i < 16; i++) { > +#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) > + if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) > + /* No need for a INT source override structure. */ > + continue; > + memset(intsrcovr, 0, sizeof(*intsrcovr)); > + intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE; > + intsrcovr->length = sizeof(*intsrcovr); > + intsrcovr->source = i; > + intsrcovr->gsi = cpu_to_le32(i); > + intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ > + intsrcovr++; > + } > + > + local_nmi = (void*)intsrcovr; > + local_nmi->type = ACPI_APIC_LOCAL_NMI; > + local_nmi->length = sizeof(*local_nmi); > + local_nmi->processor_id = 0xff; /* all processors */ > + local_nmi->flags = cpu_to_le16(0); > + local_nmi->lint = 1; /* ACPI_LINT1 */ > + local_nmi++; > + > + build_header(linker, table_data, > + (void*)madt, ACPI_APIC_SIGNATURE, > + (void*)local_nmi - (void*)madt, 1); > +} > + > +/* Encode a hex value */ > +static inline char acpi_get_hex(uint32_t val) { > + val &= 0x0f; > + return (val <= 9) ? ('0' + val) : ('A' + val - 10); > +} > + > +/* Encode a length in an SSDT. */ > +static uint8_t * > +acpi_encode_len(uint8_t *ssdt_ptr, int length, int bytes) > +{ > + switch (bytes) { > + default: > + case 4: ssdt_ptr[3] = ((length >> 20) & 0xff); > + case 3: ssdt_ptr[2] = ((length >> 12) & 0xff); > + case 2: ssdt_ptr[1] = ((length >> 4) & 0xff); > + ssdt_ptr[0] = (((bytes - 1) & 0x3) << 6) | (length & 0x0f); > + break; > + case 1: ssdt_ptr[0] = length & 0x3f; > + } > + return ssdt_ptr + bytes; > +} > + > +#include "hw/i386/ssdt-proc.hex" > + > +/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */ > +#define ACPI_PROC_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2) > +#define ACPI_PROC_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4) > +#define ACPI_PROC_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start) > +#define ACPI_PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start) > +#define ACPI_PROC_AML (ssdp_proc_aml + *ssdt_proc_start) > + > +/* 0x5B 0x82 DeviceOp PkgLength NameString */ > +#define ACPI_PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1) > +#define ACPI_PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start) > +#define ACPI_PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start) > +#define ACPI_PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start) > +#define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start) > +#define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) > + > +#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */ > +#define ACPI_SSDT_HEADER_LENGTH 36 > + > +#include "hw/i386/ssdt-misc.hex" > +#include "hw/i386/ssdt-pcihp.hex" > + > +static uint8_t* > +build_notify(uint8_t *ssdt_ptr, const char *name, int skip, int count, > + const char *target, int ofs) > +{ > + int i; > + > + count -= skip; > + > + *(ssdt_ptr++) = 0x14; /* MethodOp */ > + ssdt_ptr = acpi_encode_len(ssdt_ptr, 2+5+(12*count), 2); > + memcpy(ssdt_ptr, name, 4); > + ssdt_ptr += 4; > + *(ssdt_ptr++) = 0x02; /* MethodOp */ > + > + for (i = skip; count-- > 0; i++) { > + *(ssdt_ptr++) = 0xA0; /* IfOp */ > + ssdt_ptr = acpi_encode_len(ssdt_ptr, 11, 1); > + *(ssdt_ptr++) = 0x93; /* LEqualOp */ > + *(ssdt_ptr++) = 0x68; /* Arg0Op */ > + *(ssdt_ptr++) = 0x0A; /* BytePrefix */ > + *(ssdt_ptr++) = i; > + *(ssdt_ptr++) = 0x86; /* NotifyOp */ > + memcpy(ssdt_ptr, target, 4); > + ssdt_ptr[ofs] = acpi_get_hex(i >> 4); > + ssdt_ptr[ofs + 1] = acpi_get_hex(i); > + ssdt_ptr += 4; > + *(ssdt_ptr++) = 0x69; /* Arg1Op */ > + } > + return ssdt_ptr; > +} > + > +static void patch_pcihp(int slot, uint8_t *ssdt_ptr, uint32_t eject) > +{ > + ssdt_ptr[ACPI_PCIHP_OFFSET_HEX] = acpi_get_hex(slot >> 4); > + ssdt_ptr[ACPI_PCIHP_OFFSET_HEX+1] = acpi_get_hex(slot); > + ssdt_ptr[ACPI_PCIHP_OFFSET_ID] = slot; > + ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot; > + > + /* Runtime patching of ACPI_EJ0: to disable hotplug for a slot, > + * replace the method name: _EJ0 by ACPI_EJ0_. */ > + /* Sanity check */ > + assert (!memcmp(ssdt_ptr + ACPI_PCIHP_OFFSET_EJ0, "_EJ0", 4)); > + > + if (!eject) { > + memcpy(ssdt_ptr + ACPI_PCIHP_OFFSET_EJ0, "EJ0_", 4); > + } > +} > + > +static void > +build_ssdt(GArray *table_data, GArray *linker, > + FWCfgState *fw_cfg, PcGuestInfo *guest_info) > +{ > + int acpi_cpus = MIN(0xff, guest_info->apic_id_limit); > + int length = (sizeof(ssdp_misc_aml) /* _S3_ / _S4_ / _S5_ */ > + + (1+3+4) /* Scope(_SB_) */ > + + (acpi_cpus * ACPI_PROC_SIZEOF) /* procs */ > + + (1+2+5+(12*acpi_cpus)) /* NTFY */ > + + (6+2+1+(1*acpi_cpus)) /* CPON */ > + + (1+3+4) /* Scope(PCI0) */ > + + ((PCI_SLOT_MAX - 1) * ACPI_PCIHP_SIZEOF) /* slots */ > + + (1+2+5+(12*(PCI_SLOT_MAX - 1)))); /* PCNT */ > + uint8_t *ssdt = acpi_data_push(table_data, length); > + uint8_t *ssdt_ptr = ssdt; > + > + /* Copy header and encode fwcfg values in the S3_ / S4_ / S5_ packages */ > + memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml)); > + if (guest_info->s3_disabled) { > + ssdt_ptr[acpi_s3_name[0]] = 'X'; > + } > + if (guest_info->s4_disabled) { > + ssdt_ptr[acpi_s4_name[0]] = 'X'; > + } else { > + ssdt_ptr[acpi_s4_pkg[0] + 1] = ssdt[acpi_s4_pkg[0] + 3] = > + guest_info->s4_val; > + } > + > + *(uint32_t*)&ssdt_ptr[acpi_pci32_start[0]] = > + cpu_to_le32(guest_info->pci_info.w32.begin); > + *(uint32_t*)&ssdt_ptr[acpi_pci32_end[0]] = > + cpu_to_le32(guest_info->pci_info.w32.end - 1); I don't think you're guaranteed natural alignment here so you need to use memcpys. Regards, Anthony Liguori > + > + if (guest_info->pci_info.w64.end > guest_info->pci_info.w64.begin) { > + ssdt_ptr[acpi_pci64_valid[0]] = 1; > + *(uint64_t*)&ssdt_ptr[acpi_pci64_start[0]] = > + cpu_to_le64(guest_info->pci_info.w64.begin); > + *(uint64_t*)&ssdt_ptr[acpi_pci64_end[0]] = > + cpu_to_le64(guest_info->pci_info.w64.end - 1); > + *(uint64_t*)&ssdt_ptr[acpi_pci64_length[0]] = > + cpu_to_le64(guest_info->pci_info.w64.end - > + guest_info->pci_info.w64.begin); > + } else { > + ssdt_ptr[acpi_pci64_valid[0]] = 0; > + } > + > + *(uint16_t *)(ssdt_ptr + *ssdt_isa_pest) = > + cpu_to_le16(guest_info->pvpanic_port); > + > + ssdt_ptr += sizeof(ssdp_misc_aml); > + > + /* build Scope(_SB_) header */ > + *(ssdt_ptr++) = 0x10; /* ScopeOp */ > + ssdt_ptr = acpi_encode_len(ssdt_ptr, length - (ssdt_ptr - ssdt), 3); > + *(ssdt_ptr++) = '_'; > + *(ssdt_ptr++) = 'S'; > + *(ssdt_ptr++) = 'B'; > + *(ssdt_ptr++) = '_'; > + > + /* build Processor object for each processor */ > + int i; > + for (i=0; i + memcpy(ssdt_ptr, ACPI_PROC_AML, ACPI_PROC_SIZEOF); > + ssdt_ptr[ACPI_PROC_OFFSET_CPUHEX] = acpi_get_hex(i >> 4); > + ssdt_ptr[ACPI_PROC_OFFSET_CPUHEX+1] = acpi_get_hex(i); > + ssdt_ptr[ACPI_PROC_OFFSET_CPUID1] = i; > + ssdt_ptr[ACPI_PROC_OFFSET_CPUID2] = i; > + ssdt_ptr += ACPI_PROC_SIZEOF; > + } > + > + /* build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}" */ > + /* Arg0 = Processor ID = APIC ID */ > + ssdt_ptr = build_notify(ssdt_ptr, "NTFY", 0, acpi_cpus, "CP00", 2); > + > + /* build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })" */ > + *(ssdt_ptr++) = 0x08; /* NameOp */ > + *(ssdt_ptr++) = 'C'; > + *(ssdt_ptr++) = 'P'; > + *(ssdt_ptr++) = 'O'; > + *(ssdt_ptr++) = 'N'; > + *(ssdt_ptr++) = 0x12; /* PackageOp */ > + ssdt_ptr = acpi_encode_len(ssdt_ptr, 2+1+(1*acpi_cpus), 2); > + *(ssdt_ptr++) = acpi_cpus; > + for (i=0; i + *(ssdt_ptr++) = (test_bit(i, guest_info->found_cpus)) ? 0x01 : 0x00; > + > + /* build Scope(PCI0) opcode */ > + *(ssdt_ptr++) = 0x10; /* ScopeOp */ > + ssdt_ptr = acpi_encode_len(ssdt_ptr, length - (ssdt_ptr - ssdt), 3); > + *(ssdt_ptr++) = 'P'; > + *(ssdt_ptr++) = 'C'; > + *(ssdt_ptr++) = 'I'; > + *(ssdt_ptr++) = '0'; > + > + /* build Device object for each slot */ > + for (i = 1; i < PCI_SLOT_MAX; i++) { > + bool eject = test_bit(i, guest_info->slot_hotplug_enable); > + memcpy(ssdt_ptr, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); > + patch_pcihp(i, ssdt_ptr, eject); > + ssdt_ptr += ACPI_PCIHP_SIZEOF; > + } > + > + ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOT_MAX, "S00_", 1); > + > + build_header(linker, table_data, > + (void*)ssdt, ACPI_SSDT_SIGNATURE, ssdt_ptr - ssdt, 1); > +} > + > +static void > +build_hpet(GArray *table_data, GArray *linker) > +{ > + Acpi20Hpet *hpet; > + > + hpet = acpi_data_push(table_data, sizeof(*hpet)); > + /* Note timer_block_id value must be kept in sync with value advertised by > + * emulated hpet > + */ > + hpet->timer_block_id = cpu_to_le32(0x8086a201); > + hpet->addr.address = cpu_to_le64(HPET_BASE); > + build_header(linker, table_data, > + (void*)hpet, ACPI_HPET_SIGNATURE, sizeof(*hpet), 1); > +} > + > +static void > +acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, > + uint64_t base, uint64_t len, int node, int enabled) > +{ > + numamem->type = ACPI_SRAT_MEMORY; > + numamem->length = sizeof(*numamem); > + memset(numamem->proximity, 0, 4); > + numamem->proximity[0] = node; > + numamem->flags = cpu_to_le32(!!enabled); > + numamem->base_addr = cpu_to_le64(base); > + numamem->range_length = cpu_to_le64(len); > +} > + > +static void > +build_srat(GArray *table_data, GArray *linker, > + FWCfgState *fw_cfg, PcGuestInfo *guest_info) > +{ > + AcpiSystemResourceAffinityTable *srat; > + AcpiSratProcessorAffinity *core; > + AcpiSratMemoryAffinity *numamem; > + > + int i; > + uint64_t curnode; > + int srat_size; > + int slots; > + uint64_t mem_len, mem_base, next_base; > + > + srat_size = sizeof(*srat) + > + sizeof(AcpiSratProcessorAffinity) * guest_info->apic_id_limit + > + sizeof(AcpiSratMemoryAffinity) * (guest_info->numa_nodes + 2); > + > + srat = acpi_data_push(table_data, srat_size); > + srat->reserved1 = cpu_to_le32(1); > + core = (void*)(srat + 1); > + > + for (i = 0; i < guest_info->apic_id_limit; ++i) { > + core->type = ACPI_SRAT_PROCESSOR; > + core->length = sizeof(*core); > + core->local_apic_id = i; > + curnode = guest_info->node_cpu[i]; > + core->proximity_lo = curnode; > + memset(core->proximity_hi, 0, 3); > + core->local_sapic_eid = 0; > + if (test_bit(i, guest_info->found_cpus)) > + core->flags = cpu_to_le32(1); > + else > + core->flags = cpu_to_le32(0); > + core++; > + } > + > + > + /* the memory map is a bit tricky, it contains at least one hole > + * from 640k-1M and possibly another one from 3.5G-4G. > + */ > + numamem = (void*)core; > + slots = 0; > + next_base = 0; > + > + acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1); > + next_base = 1024 * 1024; > + numamem++; > + slots++; > + for (i = 1; i < guest_info->numa_nodes + 1; ++i) { > + mem_base = next_base; > + mem_len = guest_info->node_mem[i - 1]; > + if (i == 1) > + mem_len -= 1024 * 1024; > + next_base = mem_base + mem_len; > + > + /* Cut out the ACPI_PCI hole */ > + if (mem_base <= guest_info->ram_size && > + next_base > guest_info->ram_size) { > + mem_len -= next_base - guest_info->ram_size; > + if (mem_len > 0) { > + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); > + numamem++; > + slots++; > + } > + mem_base = 1ULL << 32; > + mem_len = next_base - guest_info->ram_size; > + next_base += (1ULL << 32) - guest_info->ram_size; > + } > + acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); > + numamem++; > + slots++; > + } > + for (; slots < guest_info->numa_nodes + 2; slots++) { > + acpi_build_srat_memory(numamem, 0, 0, 0, 0); > + numamem++; > + } > + > + build_header(linker, table_data, > + (void*)srat, ACPI_SRAT_SIGNATURE, srat_size, 1); > +} > + > +static void > +build_mcfg_q35(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) > +{ > + AcpiTableMcfg *mcfg; > + > + int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]); > + mcfg = acpi_data_push(table_data, len); > + mcfg->allocation[0].address = cpu_to_le64(guest_info->mcfg_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 = 0xFF; > + > + build_header(linker, table_data, (void *)mcfg, ACPI_MCFG_SIGNATURE, len, 1); > +} > + > +static void > +build_dsdt(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) > +{ > + void *dsdt; > + assert(guest_info->dsdt_code && guest_info->dsdt_size); > + dsdt = acpi_data_push(table_data, guest_info->dsdt_size); > + memcpy(dsdt, guest_info->dsdt_code, guest_info->dsdt_size); > +} > + > +/* 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_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, ACPI_RSDT_SIGNATURE, rsdt_len, 1); > +} > + > +static GArray * > +build_rsdp(GArray *linker, unsigned rsdt) > +{ > + GArray *rsdp_table; > + AcpiRsdpDescriptor *rsdp; > + > + rsdp_table = g_array_new(false, true /* clear */, sizeof *rsdp); > + g_array_set_size(rsdp_table, 1); > + rsdp = (void *)rsdp_table->data; > + > + bios_linker_alloc(linker, ACPI_BUILD_RSDP_FILE, 1, true /* fseg memory */); > + > + rsdp->signature = cpu_to_le64(ACPI_RSDP_SIGNATURE); > + memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6); > + rsdp->rsdt_physical_address = cpu_to_le32(rsdt); > + /* Address to be filled by Guest linker */ > + bios_linker_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_add_checksum(linker, ACPI_BUILD_RSDP_FILE, > + rsdp, rsdp, sizeof *rsdp, &rsdp->checksum); > + > + return rsdp_table; > +} > + > +static void acpi_add_rom_blob(PcGuestInfo *guest_info, GArray *blob, > + const char *name, unsigned align) > +{ > + MemoryRegion *mr = g_malloc(sizeof(*mr)); > + > + /* Align size to multiple of given size. This reduces the chance > + * we need to change size in the future (breaking cross version migration). > + */ > + g_array_set_size(blob, (ROUND_UP(acpi_data_len(blob), align) + > + g_array_get_element_size(blob) - 1) / > + g_array_get_element_size(blob)); > + memory_region_init_ram_ptr(mr, name, > + acpi_data_len(blob), blob->data); > + memory_region_set_readonly(mr, true); > + vmstate_register_ram_global(mr); > + rom_add_blob(ACPI_BUILD_TABLE_FILE, blob->data, acpi_data_len(blob), > + -1, mr); > + > + fw_cfg_add_file(guest_info->fw_cfg, name, > + blob->data, acpi_data_len(blob)); > +} > + > +#define ACPI_MAX_ACPI_TABLES 20 > +void acpi_setup(PcGuestInfo *guest_info) > +{ > + GArray *table_data, *table_offsets, *rsdp, *linker; > + unsigned facs, dsdt, rsdt; > + > + if (!guest_info->fw_cfg) { > + ACPI_BUILD_DPRINTF(3, "No fw cfg. Boiling out.\n"); > + return; > + } > + > + if (!guest_info->has_acpi_build) { > + ACPI_BUILD_DPRINTF(3, "ACPI build disabled. Boiling out.\n"); > + return; > + } > + > + table_data = g_array_new(false, true /* clear */, 1); > + table_offsets = g_array_new(false, true /* clear */, > + sizeof(uint32_t)); > + linker = bios_linker_init(); > + > + ACPI_BUILD_DPRINTF(3, "init ACPI tables\n"); > + > + bios_linker_alloc(linker, ACPI_BUILD_TABLE_FILE, 64 /* Ensure FACS is aligned */, > + false /* high memory */); > + > + /* > + * FACS is pointed to by FADT. > + * We place it first since it's the only table that has alignment > + * requirements. > + */ > + facs = table_data->len; > + build_facs(table_data, linker, guest_info); > + > + /* DSDT is pointed to by FADT */ > + dsdt = table_data->len; > + build_dsdt(table_data, linker, guest_info); > + > + /* ACPI tables pointed to by RSDT */ > + acpi_add_table(table_offsets, table_data); > + build_fadt(table_data, linker, guest_info, facs, dsdt); > + acpi_add_table(table_offsets, table_data); > + build_ssdt(table_data, linker, guest_info->fw_cfg, guest_info); > + acpi_add_table(table_offsets, table_data); > + build_madt(table_data, linker, guest_info->fw_cfg, guest_info); > + acpi_add_table(table_offsets, table_data); > + if (guest_info->has_hpet) { > + build_hpet(table_data, linker); > + } > + if (guest_info->numa_nodes) { > + acpi_add_table(table_offsets, table_data); > + build_srat(table_data, linker, guest_info->fw_cfg, guest_info); > + } > + if (guest_info->mcfg_base) { > + acpi_add_table(table_offsets, table_data); > + build_mcfg_q35(table_data, linker, guest_info); > + } > + > + /* RSDT is pointed to by RSDP */ > + rsdt = table_data->len; > + build_rsdt(table_data, linker, table_offsets); > + > + /* RSDP is in FSEG memory, so allocate it separately */ > + rsdp = build_rsdp(linker, rsdt); > + > + /* Now expose it all to Guest */ > + acpi_add_rom_blob(guest_info, table_data, > + ACPI_BUILD_TABLE_FILE, 0x10000); > + > + acpi_add_rom_blob(guest_info, linker, > + "etc/linker-script", TARGET_PAGE_SIZE); > + > + /* > + * RSDP is small so it's easy to keep it immutable, no need to > + * bother with ROM blobs. > + */ > + fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE, > + rsdp->data, acpi_data_len(rsdp)); > + > + /* Cleanup GArray wrappers and memory if no longer used. */ > + bios_linker_cleanup(linker); > + g_array_free(table_offsets, true); > + g_array_free(rsdp, false); > + g_array_free(table_data, false); > +} > diff --git a/hw/i386/acpi-defs.h b/hw/i386/acpi-defs.h > new file mode 100644 > index 0000000..e920229 > --- /dev/null > +++ b/hw/i386/acpi-defs.h > @@ -0,0 +1,327 @@ > +/* > + * 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 . > + */ > +#ifndef QEMU_ACPI_DEFS_H > +#define QEMU_ACPI_DEFS_H > + > +enum { > + ACPI_FADT_F_WBINVD, > + ACPI_FADT_F_WBINVD_FLUSH, > + ACPI_FADT_F_PROC_C1, > + ACPI_FADT_F_P_LVL2_UP, > + ACPI_FADT_F_PWR_BUTTON, > + ACPI_FADT_F_SLP_BUTTON, > + ACPI_FADT_F_FIX_RTC, > + ACPI_FADT_F_RTC_S4, > + ACPI_FADT_F_TMR_VAL_EXT, > + ACPI_FADT_F_DCK_CAP, > + ACPI_FADT_F_RESET_REG_SUP, > + ACPI_FADT_F_SEALED_CASE, > + ACPI_FADT_F_HEADLESS, > + ACPI_FADT_F_CPU_SW_SLP, > + ACPI_FADT_F_PCI_EXP_WAK, > + ACPI_FADT_F_USE_PLATFORM_CLOCK, > + ACPI_FADT_F_S4_RTC_STS_VALID, > + ACPI_FADT_F_REMOTE_POWER_ON_CAPABLE, > + ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL, > + ACPI_FADT_F_FORCE_APIC_PHYSICAL_DESTINATION_MODE, > + ACPI_FADT_F_HW_REDUCED_ACPI, > + ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE, > +}; > + > +/* > + * ACPI 2.0 Generic Address Space definition. > + */ > +struct Acpi20GenericAddress { > + uint8_t address_space_id; > + uint8_t register_bit_width; > + uint8_t register_bit_offset; > + uint8_t reserved; > + uint64_t address; > +} QEMU_PACKED; > +typedef struct Acpi20GenericAddress Acpi20GenericAddress; > + > +#define ACPI_RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR " > + > +struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */ > + uint64_t signature; /* ACPI signature, contains "RSD PTR " */ > + uint8_t checksum; /* To make sum of struct == 0 */ > + uint8_t oem_id [6]; /* OEM identification */ > + uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ > + uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ > + uint32_t length; /* XSDT Length in bytes including hdr */ > + uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ > + uint8_t extended_checksum; /* Checksum of entire table */ > + uint8_t reserved [3]; /* Reserved field must be 0 */ > +} QEMU_PACKED; > +typedef struct AcpiRsdpDescriptor AcpiRsdpDescriptor; > + > +/* Table structure from Linux kernel (the ACPI tables are under the > + BSD license) */ > + > + > +#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ > + uint32_t signature; /* ACPI signature (4 ASCII characters) */ \ > + uint32_t length; /* Length of table, in bytes, including header */ \ > + uint8_t revision; /* ACPI Specification minor version # */ \ > + uint8_t checksum; /* To make sum of entire table == 0 */ \ > + uint8_t oem_id [6]; /* OEM identification */ \ > + uint8_t oem_table_id [8]; /* OEM table identification */ \ > + uint32_t oem_revision; /* OEM revision number */ \ > + uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */ \ > + uint32_t asl_compiler_revision; /* ASL compiler revision number */ > + > + > +struct AcpiTableHeader /* ACPI common table header */ > +{ > + ACPI_TABLE_HEADER_DEF > +} QEMU_PACKED; > +typedef struct AcpiTableHeader AcpiTableHeader; > + > +/* > + * ACPI 1.0 Fixed ACPI Description Table (FADT) > + */ > +#define ACPI_FACP_SIGNATURE 0x50434146 // FACP > +struct AcpiFadtDescriptorRev1 > +{ > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + uint32_t firmware_ctrl; /* Physical address of FACS */ > + uint32_t dsdt; /* Physical address of DSDT */ > + uint8_t model; /* System Interrupt Model */ > + uint8_t reserved1; /* Reserved */ > + uint16_t sci_int; /* System vector of SCI interrupt */ > + uint32_t smi_cmd; /* Port address of SMI command port */ > + uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ > + uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ > + uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ > + uint8_t reserved2; /* Reserved - must be zero */ > + uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ > + uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ > + uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ > + uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ > + uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ > + uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ > + uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ > + uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ > + uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ > + uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ > + uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ > + uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ > + uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ > + uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ > + uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ > + uint8_t reserved3; /* Reserved */ > + uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ > + uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ > + uint16_t flush_size; /* Size of area read to flush caches */ > + uint16_t flush_stride; /* Stride used in flushing caches */ > + uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ > + uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ > + uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ > + uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ > + uint8_t century; /* Index to century in RTC CMOS RAM */ > + uint8_t reserved4; /* Reserved */ > + uint8_t reserved4a; /* Reserved */ > + uint8_t reserved4b; /* Reserved */ > + uint32_t flags; > +} QEMU_PACKED; > +typedef struct AcpiFadtDescriptorRev1 AcpiFadtDescriptorRev1; > + > +/* > + * ACPI 1.0 Root System Description Table (RSDT) > + */ > +#define ACPI_RSDT_SIGNATURE 0x54445352 // RSDT > +struct AcpiRsdtDescriptorRev1 > +{ > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + uint32_t table_offset_entry[0]; /* Array of pointers to other */ > + /* ACPI tables */ > +} QEMU_PACKED; > +typedef struct AcpiRsdtDescriptorRev1 AcpiRsdtDescriptorRev1; > + > +/* > + * ACPI 1.0 Firmware ACPI Control Structure (FACS) > + */ > +#define ACPI_FACS_SIGNATURE 0x53434146 // FACS > +struct AcpiFacsDescriptorRev1 > +{ > + uint32_t signature; /* ACPI Signature */ > + uint32_t length; /* Length of structure, in bytes */ > + uint32_t hardware_signature; /* Hardware configuration signature */ > + uint32_t firmware_waking_vector; /* ACPI OS waking vector */ > + uint32_t global_lock; /* Global Lock */ > + uint32_t flags; > + uint8_t resverved3 [40]; /* Reserved - must be zero */ > +} QEMU_PACKED; > +typedef struct AcpiFacsDescriptorRev1 AcpiFacsDescriptorRev1; > + > +/* > + * Differentiated System Description Table (DSDT) > + */ > +#define ACPI_DSDT_SIGNATURE 0x54445344 // DSDT > + > +/* > + * MADT values and structures > + */ > + > +/* Values for MADT PCATCompat */ > + > +#define ACPI_DUAL_PIC 0 > +#define ACPI_MULTIPLE_APIC 1 > + > +/* Master MADT */ > + > +#define ACPI_APIC_SIGNATURE 0x43495041 // APIC > +struct AcpiMultipleApicTable > +{ > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + uint32_t local_apic_address; /* Physical address of local APIC */ > + uint32_t flags; > +} QEMU_PACKED; > +typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; > + > +/* Values for Type in APIC sub-headers */ > + > +#define ACPI_APIC_PROCESSOR 0 > +#define ACPI_APIC_IO 1 > +#define ACPI_APIC_XRUPT_OVERRIDE 2 > +#define ACPI_APIC_NMI 3 > +#define ACPI_APIC_LOCAL_NMI 4 > +#define ACPI_APIC_ADDRESS_OVERRIDE 5 > +#define ACPI_APIC_IO_SAPIC 6 > +#define ACPI_APIC_LOCAL_SAPIC 7 > +#define ACPI_APIC_XRUPT_SOURCE 8 > +#define ACPI_APIC_RESERVED 9 /* 9 and greater are reserved */ > + > +/* > + * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) > + */ > +#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\ > + uint8_t type; \ > + uint8_t length; > + > +/* Sub-structures for MADT */ > + > +struct AcpiMadtProcessorApic > +{ > + ACPI_SUB_HEADER_DEF > + uint8_t processor_id; /* ACPI processor id */ > + uint8_t local_apic_id; /* Processor's local APIC id */ > + uint32_t flags; > +} QEMU_PACKED; > +typedef struct AcpiMadtProcessorApic AcpiMadtProcessorApic; > + > +struct AcpiMadtIoApic > +{ > + ACPI_SUB_HEADER_DEF > + uint8_t io_apic_id; /* I/O APIC ID */ > + uint8_t reserved; /* Reserved - must be zero */ > + uint32_t address; /* APIC physical address */ > + uint32_t interrupt; /* Global system interrupt where INTI > + * lines start */ > +} QEMU_PACKED; > +typedef struct AcpiMadtIoApic AcpiMadtIoApic; > + > +struct AcpiMadtIntsrcovr { > + ACPI_SUB_HEADER_DEF > + uint8_t bus; > + uint8_t source; > + uint32_t gsi; > + uint16_t flags; > +} QEMU_PACKED; > +typedef struct AcpiMadtIntsrcovr AcpiMadtIntsrcovr; > + > +struct AcpiMadtLocalNmi { > + ACPI_SUB_HEADER_DEF > + uint8_t processor_id; /* ACPI processor id */ > + uint16_t flags; /* MPS INTI flags */ > + uint8_t lint; /* Local APIC LINT# */ > +} QEMU_PACKED; > +typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi; > + > +/* > + * HPET Description Table > + */ > +#define ACPI_HPET_SIGNATURE 0x54455048 // HPET > +struct Acpi20Hpet { > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + uint32_t timer_block_id; > + Acpi20GenericAddress addr; > + uint8_t hpet_number; > + uint16_t min_tick; > + uint8_t page_protect; > +} QEMU_PACKED; > +typedef struct Acpi20Hpet Acpi20Hpet; > + > +/* > + * SRAT (NUMA topology description) table > + */ > + > +#define ACPI_SRAT_SIGNATURE 0x54415253 // SRAT > +struct AcpiSystemResourceAffinityTable > +{ > + ACPI_TABLE_HEADER_DEF > + uint32_t reserved1; > + uint32_t reserved2[2]; > +} QEMU_PACKED; > +typedef struct AcpiSystemResourceAffinityTable AcpiSystemResourceAffinityTable; > + > +#define ACPI_SRAT_PROCESSOR 0 > +#define ACPI_SRAT_MEMORY 1 > + > +struct AcpiSratProcessorAffinity > +{ > + ACPI_SUB_HEADER_DEF > + uint8_t proximity_lo; > + uint8_t local_apic_id; > + uint32_t flags; > + uint8_t local_sapic_eid; > + uint8_t proximity_hi[3]; > + uint32_t reserved; > +} QEMU_PACKED; > +typedef struct AcpiSratProcessorAffinity AcpiSratProcessorAffinity; > + > +struct AcpiSratMemoryAffinity > +{ > + ACPI_SUB_HEADER_DEF > + uint8_t proximity[4]; > + uint16_t reserved1; > + uint64_t base_addr; > + uint64_t range_length; > + uint32_t reserved2; > + uint32_t flags; > + uint32_t reserved3[2]; > +} QEMU_PACKED; > +typedef struct AcpiSratMemoryAffinity AcpiSratMemoryAffinity; > + > +/* PCI fw r3.0 MCFG table. */ > +/* Subtable */ > +struct AcpiMcfgAllocation { > + uint64_t address; /* Base address, processor-relative */ > + uint16_t pci_segment; /* PCI segment group number */ > + uint8_t start_bus_number; /* Starting PCI Bus number */ > + uint8_t end_bus_number; /* Final PCI Bus number */ > + uint32_t reserved; > +} QEMU_PACKED; > +typedef struct AcpiMcfgAllocation AcpiMcfgAllocation; > + > +#define ACPI_MCFG_SIGNATURE 0x4746434d // MCFG > +struct AcpiTableMcfg { > + ACPI_TABLE_HEADER_DEF; > + uint8_t reserved[8]; > + AcpiMcfgAllocation allocation[0]; > +} QEMU_PACKED; > +typedef struct AcpiTableMcfg AcpiTableMcfg; > + > +#endif > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > index e5ebfa5..9f9207d 100644 > --- a/hw/i386/pc.c > +++ b/hw/i386/pc.c > @@ -55,6 +55,7 @@ > #include "hw/acpi/acpi.h" > #include "hw/cpu/icc_bus.h" > #include "hw/boards.h" > +#include "hw/i386/acpi-build.h" > > /* debug PC/ISA interrupts */ > //#define DEBUG_IRQ > @@ -1045,6 +1046,7 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data) > PcGuestInfoState, > machine_done); > pc_fw_cfg_guest_info(&guest_info_state->info); > + acpi_setup(&guest_info_state->info); > } > > PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c > index 3c2541a..ab176ca 100644 > --- a/hw/i386/pc_piix.c > +++ b/hw/i386/pc_piix.c > @@ -60,6 +60,7 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; > > static bool has_pvpanic = true; > static bool has_pci_info = true; > +static bool has_acpi_build = true; > > /* PC hardware initialisation */ > static void pc_init1(MemoryRegion *system_memory, > @@ -125,6 +126,7 @@ static void pc_init1(MemoryRegion *system_memory, > > guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); > > + guest_info->has_acpi_build = has_acpi_build; > guest_info->dsdt_code = AcpiDsdtAmlCode; > guest_info->dsdt_size = sizeof AcpiDsdtAmlCode; > > @@ -269,6 +271,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args) > static void pc_init_pci_1_5(QEMUMachineInitArgs *args) > { > has_pci_info = false; > + has_acpi_build = false; > pc_init_pci(args); > } > > diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c > index 50afe7c..9539807 100644 > --- a/hw/i386/pc_q35.c > +++ b/hw/i386/pc_q35.c > @@ -50,6 +50,7 @@ > > static bool has_pvpanic = true; > static bool has_pci_info = true; > +static bool has_acpi_build = true; > > /* PC hardware initialisation */ > static void pc_q35_init(QEMUMachineInitArgs *args) > @@ -111,6 +112,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) > > guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); > guest_info->has_pci_info = has_pci_info; > + guest_info->has_acpi_build = has_acpi_build; > guest_info->dsdt_code = Q35AcpiDsdtAmlCode; > guest_info->dsdt_size = sizeof Q35AcpiDsdtAmlCode; > > @@ -221,6 +223,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) > static void pc_q35_init_1_5(QEMUMachineInitArgs *args) > { > has_pci_info = false; > + has_acpi_build = false; > pc_q35_init(args); > } > > diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl > index ac11e96..a4484b8 100644 > --- a/hw/i386/ssdt-misc.dsl > +++ b/hw/i386/ssdt-misc.dsl > @@ -70,4 +70,50 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) > Zero /* reserved */ > }) > } > + > + External(\_SB.PCI0, DeviceObj) > + External(\_SB.PCI0.ISA, DeviceObj) > + > + Scope(\_SB.PCI0.ISA) { > + Device(PEVT) { > + Name(_HID, "QEMU0001") > + /* PEST will be patched to be Zero if no such device */ > + ACPI_EXTRACT_NAME_WORD_CONST ssdt_isa_pest > + Name(PEST, 0xFFFF) > + OperationRegion(PEOR, SystemIO, PEST, 0x01) > + Field(PEOR, ByteAcc, NoLock, Preserve) { > + PEPT, 8, > + } > + > + Method(_STA, 0, NotSerialized) { > + Store(PEST, Local0) > + If (LEqual(Local0, Zero)) { > + Return (0x00) > + } Else { > + Return (0x0F) > + } > + } > + > + Method(RDPT, 0, NotSerialized) { > + Store(PEPT, Local0) > + Return (Local0) > + } > + > + Method(WRPT, 1, NotSerialized) { > + Store(Arg0, PEPT) > + } > + > + Name(_CRS, ResourceTemplate() { > + IO(Decode16, 0x00, 0x00, 0x01, 0x01, IO) > + }) > + > + CreateWordField(_CRS, IO._MIN, IOMN) > + CreateWordField(_CRS, IO._MAX, IOMX) > + > + Method(_INI, 0, NotSerialized) { > + Store(PEST, IOMN) > + Store(PEST, IOMX) > + } > + } > + } > } > diff --git a/include/hw/i386/acpi-build.h b/include/hw/i386/acpi-build.h > new file mode 100644 > index 0000000..e57b1aa > --- /dev/null > +++ b/include/hw/i386/acpi-build.h > @@ -0,0 +1,9 @@ > + > +#ifndef HW_I386_ACPI_BUILD_H > +#define HW_I386_ACPI_BUILD_H > + > +#include "qemu/typedefs.h" > + > +void acpi_setup(PcGuestInfo *); > + > +#endif > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h > index b29c8f6..02cc559 100644 > --- a/include/hw/i386/pc.h > +++ b/include/hw/i386/pc.h > @@ -51,6 +51,7 @@ struct PcGuestInfo { > unsigned dsdt_size; > uint16_t pvpanic_port; > FWCfgState *fw_cfg; > + bool has_acpi_build; > }; > > /* parallel.c */ > -- > MST > > > _______________________________________________ > SeaBIOS mailing list > SeaBIOS@seabios.org > http://www.seabios.org/mailman/listinfo/seabios