On Mon, Jul 08, 2013 at 02:16:13PM -0500, Anthony Liguori wrote: > "Michael S. Tsirkin" <m...@redhat.com> 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) > > <http://thread.gmane.org/gmane.comp.bios.coreboot.seabios/5949>: > > > > 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 <email address> > > > > Acked-by: Gerd Hoffmann <kra...@redhat.com> > > Acked-by: Jan Kiszka <jan.kis...@siemens.com> > > Acked-by: Jason Baron <jba...@akamai.com> > > Acked-by: David Woodhouse <david.woodho...@intel.com> > > Acked-by: Gleb Natapov <g...@redhat.com> > > Acked-by: Marcelo Tosatti <mtosa...@redhat.com> > > Acked-by: Dave Frodin <dave.fro...@se-eng.com> > > Acked-by: Paolo Bonzini <pbonz...@redhat.com> > > Acked-by: Kevin O'Connor <ke...@koconnor.net> > > Acked-by: Laszlo Ersek <ler...@redhat.com> > > Acked-by: Kenji Kaneshige <kaneshige.ke...@jp.fujitsu.com> > > Acked-by: Isaku Yamahata <yamah...@valinux.co.jp> > > Acked-by: Magnus Christensson <magnus.christens...@intel.com> > > Acked-by: Hu Tao <hu...@cn.fujitsu.com> > > Acked-by: Eduardo Habkost <ehabk...@redhat.com> > > > > Signed-off-by: Michael S. Tsirkin <m...@redhat.com> > > --- > > 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 <ke...@koconnor.net> > > + * Copyright (C) 2006 Fabrice Bellard > > + * Copyright (C) 2013 Red Hat Inc > > + * > > + * Author: Michael S. Tsirkin <m...@redhat.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 "hw/i386/acpi-build.h" > > +#include <stddef.h> > > +#include <glib.h> > > +#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.
Absolutely, it's better. It's only like this because it's a port from seabios. In fact, I think it's best to use GArray and avoid offsets completely. But let's merge it then cleanup, this way it's easier to make sure there are no regressions. > > + 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<acpi_cpus; 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<acpi_cpus; 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 <http://www.gnu.org/licenses/>. > > + */ > > +#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 _______________________________________________ SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios