[U-Boot] [PATCH v2] Initial support for ACPI Tables for qemu-x86 target.
Bin Meng
bmeng.cn at gmail.com
Wed Jun 17 14:59:49 CEST 2015
+Simon
Hi Saket,
Since you just sent the patch to U-Boot mailing list for the first
time, this is officially the v1 patch that is visible to the mailing
list, although we know you sent us the 'v1' patch offline before.
Please check my initial review comments below. I will continue
reviewing after I checked the specs.
On Wed, Jun 17, 2015 at 10:25 AM, Saket Sinha <saket.sinha89 at gmail.com> wrote:
> This patchset is an initial attempt to support ACPI Tables for qemu-x86 target.
>
> Changes in v2:
> Dynamic generation of AML code for DSDT table.
> Reading PCI registers for FADT table.
> Incorporated Simon's review comments.
>
In the future, please do not include the changelog in the commit
message. Instead, put it below the 'Signed-off-by:'.
> Signed-off-by: Saket Sinha <saket.sinha89 at gmail.com>
> ---
> Makefile | 5 +
> arch/x86/Kconfig | 5 +
> arch/x86/cpu/qemu/Makefile | 2 +-
> arch/x86/cpu/qemu/acpi_table.c | 575 ++++++++++++++++++++++++++++++++++++++
> arch/x86/cpu/qemu/cpu-hotplug.asl | 78 ++++++
> arch/x86/cpu/qemu/dbug.asl | 26 ++
> arch/x86/cpu/qemu/dsdt.asl | 221 +++++++++++++++
> arch/x86/cpu/qemu/hpet.asl | 36 +++
> arch/x86/cpu/qemu/pci-crs.asl | 94 +++++++
> arch/x86/include/asm/acpi_table.h | 318 +++++++++++++++++++++
> arch/x86/include/asm/acpigen.h | 85 ++++++
> arch/x86/lib/tables.c | 5 +
> configs/qemu-x86_defconfig | 1 +
> 13 files changed, 1450 insertions(+), 1 deletion(-)
> create mode 100755 arch/x86/cpu/qemu/acpi_table.c
> create mode 100644 arch/x86/cpu/qemu/cpu-hotplug.asl
> create mode 100644 arch/x86/cpu/qemu/dbug.asl
> create mode 100644 arch/x86/cpu/qemu/dsdt.asl
> create mode 100644 arch/x86/cpu/qemu/hpet.asl
> create mode 100644 arch/x86/cpu/qemu/pci-crs.asl
> create mode 100755 arch/x86/include/asm/acpi_table.h
> create mode 100755 arch/x86/include/asm/acpigen.h
>
> diff --git a/Makefile b/Makefile
> index 0a674bf..94388e6 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -389,6 +389,11 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
> # ===========================================================================
> # Rules shared between *config targets and build targets
>
> +PHONY += acpi
> +acpi:
> + $(Q)iasl -p dsdt -tc arch/x86/cpu/qemu/dsdt.asl
> + $(Q)mv dsdt.hex arch/x86/cpu/qemu/dsdt.c
> +
Please do not use hardcoded path here to compile the asl file.
> # Basic helpers built in scripts/
> PHONY += scripts_basic
> scripts_basic:
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 1aeae9d..c44ac07 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -321,6 +321,11 @@ config GENERATE_SFI_TABLE
>
> endmenu
>
> +config GENERATE_ACPI_TABLE
> + bool "Generate ACPI(Advanced Configuration and Power Interface) table"
Please include a help paragraph to describe the ACPI table.
> + default y
We should say 'default n' here.
> +
> +
> config MAX_PIRQ_LINKS
> int
> default 8
> diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile
> index be79723..3a570bb 100644
> --- a/arch/x86/cpu/qemu/Makefile
> +++ b/arch/x86/cpu/qemu/Makefile
> @@ -4,5 +4,5 @@
> # SPDX-License-Identifier: GPL-2.0+
> #
>
> -obj-y += car.o dram.o qemu.o
> +obj-y += car.o dram.o qemu.o dsdt.o acpi_table.o
> obj-$(CONFIG_PCI) += pci.o
> diff --git a/arch/x86/cpu/qemu/acpi_table.c b/arch/x86/cpu/qemu/acpi_table.c
> new file mode 100755
> index 0000000..cefd5f4
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/acpi_table.c
> @@ -0,0 +1,575 @@
> +#include <asm/acpigen.h>
> +#include <asm/acpi_table.h>
> +#include <asm/cpu.h>
> +#include <asm/ioapic.h>
> +#include <asm/sfi.h>
I don't think <asm/sfi.h> is need here.
> +#include <asm/tables.h>
> +#include <asm/pci.h>
> +#include <cpu.h>
> +#include <dm.h>
> +#include <dm/uclass-internal.h>
> +#include <dm/lists.h>
> +
> +#define LOCAL_APIC_ADDR 0xfee0000
Please use the macro directly from <asm/lapic.h>
> +
> +extern const unsigned char AmlCode[];
Please do not use camel case.
> +
> +u8 acpi_checksum(u8 *table, u32 length)
> +{
> + u8 ret = 0;
> + while (length--) {
> + ret += *table;
> + table++;
> + }
> + return -ret;
> +}
Please use table_compute_checksum() from tables.c
> +/**
> + * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
> + * and checksum.
> + */
> +void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
> +{
> + int i, entries_num;
> + struct acpi_rsdt *rsdt;
> + struct acpi_xsdt *xsdt = NULL;
> +
> + /* The RSDT is mandatory... */
> + rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
> +
> + /* ...while the XSDT is not. */
> + if (rsdp->xsdt_address)
> + xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
(u32) cast is a must?
> +
> + /* This should always be MAX_ACPI_TABLES. */
> + entries_num = ARRAY_SIZE(rsdt->entry);
> +
> + for (i = 0; i < entries_num; i++) {
> + if (rsdt->entry[i] == 0)
> + break;
> + }
> +
> + if (i >= entries_num) {
> + printf("ACPI: Error: Could not add ACPI table, "
> + "too many tables.\n");
Use debug()
> + return;
> + }
> +
> + /* Add table to the RSDT. */
> + rsdt->entry[i] = (u32)table;
> +
> + /* Fix RSDT length or the kernel will assume invalid entries. */
> + rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
> +
> + /* Re-calculate checksum. */
> + rsdt->header.checksum = 0; /* Hope this won't get optimized away */
This might get optimized. Can we memset() the rsdt in the beginning?
> + rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length);
> +
> + /*
> + * And now the same thing for the XSDT. We use the same index as for
> + * now we want the XSDT and RSDT to always be in sync in coreboot.
> + */
> + if (xsdt) {
> + /* Add table to the XSDT. */
> + xsdt->entry[i] = (u64)(u32)table;
> +
> + /* Fix XSDT length. */
> + xsdt->header.length = sizeof(acpi_header_t) +
> + (sizeof(u64) * (i + 1));
> +
> + /* Re-calculate checksum. */
> + xsdt->header.checksum = 0;
> + xsdt->header.checksum = acpi_checksum((u8 *)xsdt,
> + xsdt->header.length);
> + }
> +
> +}
> +
> +static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, u8 cpu, u8 apic)
> +{
> + lapic->type = 0; /* Local APIC structure */
> + lapic->length = sizeof(struct acpi_madt_lapic);
> + lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
> + lapic->processor_id = cpu;
> + lapic->apic_id = apic;
> +
> + return lapic->length;
> +}
> +
> +static unsigned long acpi_create_madt_lapics(unsigned long current)
> +{
> + struct udevice *dev;
> +
> + for (uclass_find_first_device(UCLASS_CPU, &dev);
> + dev;
> + uclass_find_next_device(&dev)) {
> + struct cpu_platdata *plat = dev_get_parent_platdata(dev);
> +
> + current += acpi_create_madt_lapic((struct acpi_madt_lapic *)current, plat->cpu_id, plat->cpu_id);
> + }
The indention of the above block looks wrong. Please fix.
> + return current;
> +}
> +
> +static int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
> + u32 gsi_base)
> +{
> + ioapic->type = 1; /* I/O APIC structure */
Please avoid using magic number here. Instead use enum for all ACPI tables.
> + ioapic->length = sizeof(struct acpi_madt_ioapic);
> + ioapic->reserved = 0x00;
> + ioapic->gsi_base = gsi_base;
> + ioapic->ioapic_id = id;
> + ioapic->ioapic_addr = addr;
> +
> + return ioapic->length;
> +}
> +
> +static int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
> + u8 bus, u8 source, u32 gsirq, u16 flags)
> +{
> + irqoverride->type = 2; /* Interrupt source override */
> + irqoverride->length = sizeof(struct acpi_madt_irqoverride);
> + irqoverride->bus = bus;
> + irqoverride->source = source;
> + irqoverride->gsirq = gsirq;
> + irqoverride->flags = flags;
> +
> + return irqoverride->length;
> +}
> +
> +#define IO_APIC_ADDR 0xfec00000
Please use macro from <asm/ioapic.h>
> +static unsigned long acpi_fill_madt(unsigned long current)
> +{
> + /* create all subtables for processors */
> + current = acpi_create_madt_lapics(current);
> +
> + /* Write SB800 IOAPIC, only one */
> + current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *) current, 2,
> + IO_APIC_ADDR, 0);
> +
> + current += acpi_create_madt_irqoverride((struct acpi_madt_irqoverride *)
> + current, 0, 0, 2, 0);
> + current += acpi_create_madt_irqoverride((struct acpi_madt_irqoverride *)
> + current, 0, 9, 9, 0xF);
> + /* 0: mean bus 0--->ISA */
> + /* 0: PIC 0 */
> + /* 2: APIC 2 */
> + /* 5 mean: 0101 --> Edge-triggered, Active high */
> +
> + return current;
> +}
> +
> +static void acpi_create_madt(struct acpi_madt *madt)
> +{
> + acpi_header_t *header = &(madt->header);
> + unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt);
> +
> + memset((void *)madt, 0, sizeof(struct acpi_madt));
> +
> + /* Fill out header fields. */
> + memcpy(header->signature, "APIC", 4);
> + memcpy(header->oem_id, OEM_ID, 6);
> + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
> + memcpy(header->asl_compiler_id, ASLC, 4);
> +
> + header->length = sizeof(struct acpi_madt);
> + header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
Please define macros for the ACPI version numbers.
> +
> + madt->lapic_addr = LOCAL_APIC_ADDR;
> + madt->flags = 0x1; /* PCAT_COMPAT */
macro
> +
> + current = acpi_fill_madt(current);
> +
> + /* (Re)calculate length and checksum. */
> + header->length = current - (unsigned long)madt;
> +
> + header->checksum = acpi_checksum((void *)madt, header->length);
> +}
> +
> +static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
> + u16 seg_nr, u8 start, u8 end)
> +{
> + memset(mmconfig, 0, sizeof(*mmconfig));
> + mmconfig->base_address = base;
> + mmconfig->base_reserved = 0;
> + mmconfig->pci_segment_group_number = seg_nr;
> + mmconfig->start_bus_number = start;
> + mmconfig->end_bus_number = end;
> +
> + return sizeof(struct acpi_mcfg_mmconfig);
> +}
> +
> +static unsigned long acpi_fill_mcfg(unsigned long current)
> +{
> + pci_dev_t qemu_dev;
> + struct pci_device_id qemu_id[] = { { 0x8086, 0x29c0 } };
> + u32 reg;
> +
> + qemu_dev = pci_find_devices(qemu_id, 0);
> + if (!qemu_dev)
> + return current;
> +
> + reg = pci_read_config_dword(qemu_dev, 0x60, ®);
> + if ((reg & 0x07) != 0x01) // require enabled + 256MB size
> + return current;
> +
> + current += acpi_create_mcfg_mmconfig((struct acpi_mcfg_mmconfig *) current,
> + reg & 0xf0000000, 0x0, 0x0, 255);
> +
> + return current;
> +}
> +
> +/* MCFG is defined in the PCI Firmware Specification 3.0. */
> +static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
> +{
> + acpi_header_t *header = &(mcfg->header);
> + unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg);
> +
> + memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
> +
> + /* Fill out header fields. */
> + memcpy(header->signature, "MCFG", 4);
> + memcpy(header->oem_id, OEM_ID, 6);
> + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
> + memcpy(header->asl_compiler_id, ASLC, 4);
> +
> + header->length = sizeof(struct acpi_mcfg);
> + header->revision = 1;
> +
> + current = acpi_fill_mcfg(current);
> +
> + /* (Re)calculate length and checksum. */
> + header->length = current - (unsigned long)mcfg;
> + header->checksum = acpi_checksum((void *)mcfg, header->length);
> +}
> +
> +static void acpi_create_facs(struct acpi_facs *facs)
> +{
> + memset((void *)facs, 0, sizeof(struct acpi_facs));
> +
> + memcpy(facs->signature, "FACS", 4);
> + facs->length = sizeof(struct acpi_facs);
> + facs->hardware_signature = 0;
> + facs->firmware_waking_vector = 0;
> + facs->global_lock = 0;
> + facs->flags = 0;
> + facs->x_firmware_waking_vector_l = 0;
> + facs->x_firmware_waking_vector_h = 0;
> + facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
> +}
> +
> +static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
> +{
> + acpi_header_t *header = &(rsdt->header);
> +
> + /* Fill out header fields. */
> + memcpy(header->signature, "RSDT", 4);
> + memcpy(header->oem_id, OEM_ID, 6);
> + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
> + memcpy(header->asl_compiler_id, ASLC, 4);
> +
> + header->length = sizeof(struct acpi_rsdt);
> + header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */
> +
> + /* Entries are filled in later, we come with an empty set. */
> +
> + /* Fix checksum. */
> + header->checksum = acpi_checksum((void *)rsdt, sizeof(struct acpi_rsdt));
> +}
> +
> +static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
> +{
> + acpi_header_t *header = &(xsdt->header);
> +
> + /* Fill out header fields. */
> + memcpy(header->signature, "XSDT", 4);
> + memcpy(header->oem_id, OEM_ID, 6);
> + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
> + memcpy(header->asl_compiler_id, ASLC, 4);
> +
> + header->length = sizeof(struct acpi_xsdt);
> + header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */
> +
> + /* Entries are filled in later, we come with an empty set. */
> +
> + /* Fix checksum. */
> + header->checksum = acpi_checksum((void *)xsdt, sizeof(struct acpi_xsdt));
> +}
> +
> +static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, struct acpi_xsdt *xsdt)
> +{
> + memset(rsdp, 0, sizeof(struct acpi_rsdp));
> +
> + memcpy(rsdp->signature, RSDP_SIG, 8);
> + memcpy(rsdp->oem_id, OEM_ID, 6);
> +
> + rsdp->length = sizeof(struct acpi_rsdp);
> + rsdp->rsdt_address = (u32)rsdt;
> +
> + /*
> + * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2.
> + *
> + * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
> + * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
> + * revision 0).
> + */
> + if (xsdt == NULL) {
> + rsdp->revision = 0;
> + } else {
> + rsdp->xsdt_address = (u64)(u32)xsdt;
> + rsdp->revision = 2;
> + }
> +
> + /* Calculate checksums. */
> + rsdp->checksum = acpi_checksum((void *)rsdp, 20);
> + rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(struct acpi_rsdp));
> +}
> +
> +static void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, void *dsdt)
> +{
> + acpi_header_t *header = &(fadt->header);
> + u16 pmbase;
> +
> + pci_dev_t bdf = PCI_BDF(0, 0x1f, 0);
> + pci_read_config_word(bdf, 0x40, &pmbase);
> +
> + memset((void *) fadt, 0, sizeof(struct acpi_fadt));
> + memcpy(header->signature, "FACP", 4);
> + header->length = sizeof(struct acpi_fadt);
> + header->revision = 3;
> + memcpy(header->oem_id, OEM_ID, 6);
> + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
> + memcpy(header->asl_compiler_id, ASLC, 4);
> + header->asl_compiler_revision = 0;
> +
> + fadt->firmware_ctrl = (unsigned long) facs;
> + fadt->dsdt = (unsigned long) dsdt;
> + fadt->model = 0x00;
> + fadt->preferred_pm_profile = PM_MOBILE;
> + fadt->sci_int = 0x9;
> + fadt->smi_cmd = 0;
> + fadt->acpi_enable = 0;
> + fadt->acpi_disable = 0;
> + fadt->s4bios_req = 0x0;
> + fadt->pstate_cnt = 0;
> + fadt->pm1a_evt_blk = pmbase;
> + fadt->pm1b_evt_blk = 0x0;
> + fadt->pm1a_cnt_blk = pmbase + 0x4;
> + fadt->pm1b_cnt_blk = 0x0;
> + fadt->pm2_cnt_blk = pmbase + 0x50;
> + fadt->pm_tmr_blk = pmbase + 0x8;
> + fadt->gpe0_blk = pmbase + 0x20;
> + fadt->gpe1_blk = 0;
> + fadt->pm1_evt_len = 4;
> + fadt->pm1_cnt_len = 2; /* Upper word is reserved and
> + Linux complains about 32 bit. */
> + fadt->pm2_cnt_len = 1;
> + fadt->pm_tmr_len = 4;
> + fadt->gpe0_blk_len = 16;
> + fadt->gpe1_blk_len = 0;
> + fadt->gpe1_base = 0;
> + fadt->cst_cnt = 0;
> + fadt->p_lvl2_lat = 1;
> + fadt->p_lvl3_lat = 0x39;
> + fadt->flush_size = 0;
> + fadt->flush_stride = 0;
> + fadt->duty_offset = 1;
> + fadt->duty_width = 3;
> + fadt->day_alrm = 0xd;
> + fadt->mon_alrm = 0x00;
> + fadt->century = 0x32;
> + fadt->iapc_boot_arch = 0x00;
> + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
> + ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE |
> + ACPI_FADT_DOCKING_SUPPORTED | ACPI_FADT_RESET_REGISTER |
> + ACPI_FADT_PLATFORM_CLOCK;
> + fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
> + fadt->reset_reg.bit_width = 8;
> + fadt->reset_reg.bit_offset = 0;
> + fadt->reset_reg.resv = 0;
> + fadt->reset_reg.addrl = 0xcf9;
> + fadt->reset_reg.addrh = 0;
> + fadt->reset_value = 0x06;
> + fadt->x_firmware_ctl_l = 0; /* Set X_FIRMWARE_CTRL only if FACS is */
> + fadt->x_firmware_ctl_h = 0; /* above 4GB. If X_FIRMWARE_CTRL is set, */
> + /* then FIRMWARE_CTRL must be zero. */
> +
> + fadt->x_dsdt_l = (unsigned long)dsdt;
> + fadt->x_dsdt_h = 0;
> + fadt->x_pm1a_evt_blk.space_id = 1;
> + fadt->x_pm1a_evt_blk.bit_width = 32;
> + fadt->x_pm1a_evt_blk.bit_offset = 0;
> + fadt->x_pm1a_evt_blk.resv = 0;
> + fadt->x_pm1a_evt_blk.addrl = pmbase;
> + fadt->x_pm1a_evt_blk.addrh = 0x0;
> + fadt->x_pm1b_evt_blk.space_id = 0;
> + fadt->x_pm1b_evt_blk.bit_width = 0;
> + fadt->x_pm1b_evt_blk.bit_offset = 0;
> + fadt->x_pm1b_evt_blk.resv = 0;
> + fadt->x_pm1b_evt_blk.addrl = 0x0;
> + fadt->x_pm1b_evt_blk.addrh = 0x0;
> + fadt->x_pm1a_cnt_blk.space_id = 1;
> + fadt->x_pm1a_cnt_blk.bit_width = 16; /* Upper word is reserved and
> + Linux complains about 32 bit. */
> + fadt->x_pm1a_cnt_blk.bit_offset = 0;
> + fadt->x_pm1a_cnt_blk.resv = 0;
> + fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
> + fadt->x_pm1a_cnt_blk.addrh = 0x0;
> + fadt->x_pm1b_cnt_blk.space_id = 0;
> + fadt->x_pm1b_cnt_blk.bit_width = 0;
> + fadt->x_pm1b_cnt_blk.bit_offset = 0;
> + fadt->x_pm1b_cnt_blk.resv = 0;
> + fadt->x_pm1b_cnt_blk.addrl = 0x0;
> + fadt->x_pm1b_cnt_blk.addrh = 0x0;
> + fadt->x_pm2_cnt_blk.space_id = 1;
> + fadt->x_pm2_cnt_blk.bit_width = 8;
> + fadt->x_pm2_cnt_blk.bit_offset = 0;
> + fadt->x_pm2_cnt_blk.resv = 0;
> + fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
> + fadt->x_pm2_cnt_blk.addrh = 0x0;
> + fadt->x_pm_tmr_blk.space_id = 1;
> + fadt->x_pm_tmr_blk.bit_width = 32;
> + fadt->x_pm_tmr_blk.bit_offset = 0;
> + fadt->x_pm_tmr_blk.resv = 0;
> + fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
> + fadt->x_pm_tmr_blk.addrh = 0x0;
> + fadt->x_gpe0_blk.space_id = 1;
> + fadt->x_gpe0_blk.bit_width = 128;
> + fadt->x_gpe0_blk.bit_offset = 0;
> + fadt->x_gpe0_blk.resv = 0;
> + fadt->x_gpe0_blk.addrl = pmbase + 0x20;
> + fadt->x_gpe0_blk.addrh = 0x0;
> + fadt->x_gpe1_blk.space_id = 0;
> + fadt->x_gpe1_blk.bit_width = 0;
> + fadt->x_gpe1_blk.bit_offset = 0;
> + fadt->x_gpe1_blk.resv = 0;
> + fadt->x_gpe1_blk.addrl = 0x0;
> + fadt->x_gpe1_blk.addrh = 0x0;
> +
> + header->checksum =
> + acpi_checksum((void *) fadt, header->length);
> +
> +}
> +
> +static void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id)
> +{
> + unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
> +
> + memset((void *)ssdt, 0, sizeof(acpi_header_t));
> +
> + memcpy(&ssdt->signature, "SSDT", 4);
> + ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */
> + memcpy(&ssdt->oem_id, OEM_ID, 6);
> + memcpy(&ssdt->oem_table_id, oem_table_id, 8);
> + ssdt->oem_revision = 42;
> + memcpy(&ssdt->asl_compiler_id, ASLC, 4);
> + ssdt->asl_compiler_revision = 42;
> + ssdt->length = sizeof(acpi_header_t);
> +
> + /* (Re)calculate length and checksum. */
> + ssdt->length = current - (unsigned long)ssdt;
> + ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
> +}
> +
> +
> +#define ALIGN_CURRENT current = (ALIGN(current, 16))
> +unsigned long write_acpi_tables(unsigned long start)
> +{
> + unsigned long current;
> + struct acpi_rsdp *rsdp;
> + struct acpi_rsdt *rsdt;
> + struct acpi_xsdt *xsdt;
> + struct acpi_facs *facs;
> + acpi_header_t *dsdt;
> + struct acpi_fadt *fadt;
> + struct acpi_mcfg *mcfg;
> + struct acpi_madt *madt;
> + acpi_header_t *ssdt;
> +
> + current = start;
> +
> + /* Align ACPI tables to 16byte */
> + ALIGN_CURRENT;
> +
> + printf("ACPI: Writing ACPI tables at %lx.\n", start);
> +
> + /* We need at least an RSDP and an RSDT Table */
> + rsdp = (struct acpi_rsdp *) current;
> + current += sizeof(struct acpi_rsdp);
> + ALIGN_CURRENT;
> + rsdt = (struct acpi_rsdt *) current;
> + current += sizeof(struct acpi_rsdt);
> + ALIGN_CURRENT;
> + xsdt = (struct acpi_xsdt *) current;
> + current += sizeof(struct acpi_xsdt);
> + ALIGN_CURRENT;
> +
> + /* clear all table memory */
> + memset((void *) start, 0, current - start);
> +
> + acpi_write_rsdp(rsdp, rsdt, xsdt);
> + acpi_write_rsdt(rsdt);
> + acpi_write_xsdt(xsdt);
> +
> + printf("ACPI: * FACS\n");
> + facs = (struct acpi_facs *) current;
> + current += sizeof(struct acpi_facs);
> + ALIGN_CURRENT;
> +
> + acpi_create_facs(facs);
> +
> + printf("ACPI: * DSDT\n");
> + dsdt = (acpi_header_t *) current;
> + memcpy(dsdt, &AmlCode, sizeof(acpi_header_t));
> + if (dsdt->length >= sizeof(acpi_header_t)) {
> + current += sizeof(acpi_header_t);
> + memcpy((char *)current,
> + (char *)&AmlCode + sizeof(acpi_header_t),
> + dsdt->length - sizeof(acpi_header_t));
> + current += dsdt->length - sizeof(acpi_header_t);
> +
> + /* (Re)calculate length and checksum. */
> + dsdt->length = current - (unsigned long)dsdt;
> + dsdt->checksum = 0;
> + dsdt->checksum = acpi_checksum((void *)dsdt, dsdt->length);
> + }
> + ALIGN_CURRENT;
> +
> + printf("ACPI: * FADT\n");
> + fadt = (struct acpi_fadt *) current;
> + current += sizeof(struct acpi_fadt);
> + ALIGN_CURRENT;
> + acpi_create_fadt(fadt, facs, dsdt);
> + acpi_add_table(rsdp, fadt);
> +
> + printf("ACPI: * MCFG\n");
> + mcfg = (struct acpi_mcfg *) current;
> + acpi_create_mcfg(mcfg);
> + if (mcfg->header.length > sizeof(struct acpi_mcfg)) {
> + current += mcfg->header.length;
> + ALIGN_CURRENT;
> + acpi_add_table(rsdp, mcfg);
> + }
> +
> + printf("ACPI: * MADT\n");
> + madt = (struct acpi_madt *) current;
> + acpi_create_madt(madt);
> + if (madt->header.length > sizeof(struct acpi_madt)) {
> + current+=madt->header.length;
> + acpi_add_table(rsdp,madt);
> + }
> + ALIGN_CURRENT;
> +
> + printf("ACPI: * SSDT\n");
> + ssdt = (acpi_header_t *)current;
> + acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR);
> + if (ssdt->length > sizeof(acpi_header_t)) {
> + current += ssdt->length;
> + acpi_add_table(rsdp, ssdt);
> + ALIGN_CURRENT;
> + }
> +
> +
> + printf("current = %lx\n", current);
> +
> + printf("ACPI: done.\n");
> + return current;
> +}
> diff --git a/arch/x86/cpu/qemu/cpu-hotplug.asl b/arch/x86/cpu/qemu/cpu-hotplug.asl
> new file mode 100644
> index 0000000..0f3e83b
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/cpu-hotplug.asl
> @@ -0,0 +1,78 @@
> +/****************************************************************
> + * CPU hotplug
> + ****************************************************************/
> +
> +Scope(\_SB) {
> + /* Objects filled in by run-time generated SSDT */
> + External(NTFY, MethodObj)
> + External(CPON, PkgObj)
> +
> + /* Methods called by run-time generated SSDT Processor objects */
> + Method(CPMA, 1, NotSerialized) {
> + // _MAT method - create an madt apic buffer
> + // Arg0 = Processor ID = Local APIC ID
> + // Local0 = CPON flag for this cpu
> + Store(DerefOf(Index(CPON, Arg0)), Local0)
> + // Local1 = Buffer (in madt apic form) to return
> + Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
> + // Update the processor id, lapic id, and enable/disable status
> + Store(Arg0, Index(Local1, 2))
> + Store(Arg0, Index(Local1, 3))
> + Store(Local0, Index(Local1, 4))
> + Return (Local1)
> + }
> + Method(CPST, 1, NotSerialized) {
> + // _STA method - return ON status of cpu
> + // Arg0 = Processor ID = Local APIC ID
> + // Local0 = CPON flag for this cpu
> + Store(DerefOf(Index(CPON, Arg0)), Local0)
> + If (Local0) {
> + Return (0xF)
> + } Else {
> + Return (0x0)
> + }
> + }
> + Method(CPEJ, 2, NotSerialized) {
> + // _EJ0 method - eject callback
> + Sleep(200)
> + }
> +
> + /* CPU hotplug notify method */
> + OperationRegion(PRST, SystemIO, 0xaf00, 32)
> + Field(PRST, ByteAcc, NoLock, Preserve) {
> + PRS, 256
> + }
> + Method(PRSC, 0) {
> + // Local5 = active cpu bitmap
> + Store(PRS, Local5)
> + // Local2 = last read byte from bitmap
> + Store(Zero, Local2)
> + // Local0 = Processor ID / APIC ID iterator
> + Store(Zero, Local0)
> + While (LLess(Local0, SizeOf(CPON))) {
> + // Local1 = CPON flag for this cpu
> + Store(DerefOf(Index(CPON, Local0)), Local1)
> + If (And(Local0, 0x07)) {
> + // Shift down previously read bitmap byte
> + ShiftRight(Local2, 1, Local2)
> + } Else {
> + // Read next byte from cpu bitmap
> + Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
> + }
> + // Local3 = active state for this cpu
> + Store(And(Local2, 1), Local3)
> +
> + If (LNotEqual(Local1, Local3)) {
> + // State change - update CPON with new state
> + Store(Local3, Index(CPON, Local0))
> + // Do CPU notify
> + If (LEqual(Local3, 1)) {
> + NTFY(Local0, 1)
> + } Else {
> + NTFY(Local0, 3)
> + }
> + }
> + Increment(Local0)
> + }
> + }
> +}
> diff --git a/arch/x86/cpu/qemu/dbug.asl b/arch/x86/cpu/qemu/dbug.asl
> new file mode 100644
> index 0000000..276321f
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/dbug.asl
> @@ -0,0 +1,26 @@
> +/****************************************************************
> + * Debugging
> + ****************************************************************/
> +
> +Scope(\) {
> + /* Debug Output */
> + OperationRegion(DBG, SystemIO, 0x0402, 0x01)
> + Field(DBG, ByteAcc, NoLock, Preserve) {
> + DBGB, 8,
> + }
> +
> + /* Debug method - use this method to send output to the QEMU
> + * BIOS debug port. This method handles strings, integers,
> + * and buffers. For example: DBUG("abc") DBUG(0x123) */
> + Method(DBUG, 1) {
> + ToHexString(Arg0, Local0)
> + ToBuffer(Local0, Local0)
> + Subtract(SizeOf(Local0), 1, Local1)
> + Store(Zero, Local2)
> + While (LLess(Local2, Local1)) {
> + Store(DerefOf(Index(Local0, Local2)), DBGB)
> + Increment(Local2)
> + }
> + Store(0x0A, DBGB)
> + }
> +}
> diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl
> new file mode 100644
> index 0000000..33c33c0
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/dsdt.asl
> @@ -0,0 +1,221 @@
> +/*
> + * Bochs/QEMU ACPI DSDT ASL definition
> + *
> + * Copyright (c) 2006 Fabrice Bellard
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc.
> + */
> +/*
> + * Copyright (c) 2010 Isaku Yamahata
> + * yamahata at valinux co jp
> + * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset.
> + */
> +
> +DefinitionBlock (
> + "dsdt.aml", // Output Filename
> + "DSDT", // Signature
> + 0x01, // DSDT Compliance Revision
> + "CORE", // OEMID
> + "COREBOOT", // TABLE ID
> + 0x2 // OEM Revision
> + )
> +{
> +
> +#include "dbug.asl"
> +
> + Scope(\_SB) {
> + OperationRegion(PCST, SystemIO, 0xae00, 0x0c)
> + OperationRegion(PCSB, SystemIO, 0xae0c, 0x01)
> + Field(PCSB, AnyAcc, NoLock, WriteAsZeros) {
> + PCIB, 8,
> + }
> + }
> +
> +
> +/****************************************************************
> + * PCI Bus definition
> + ****************************************************************/
> +
> + Scope(\_SB) {
> + Device(PCI0) {
> + Name(_HID, EisaId("PNP0A08"))
> + Name(_CID, EisaId("PNP0A03"))
> + Name(_ADR, 0x00)
> + Name(_UID, 1)
> +
> + // _OSC: based on sample of ACPI3.0b spec
> + Name(SUPP, 0) // PCI _OSC Support Field value
> + Name(CTRL, 0) // PCI _OSC Control Field value
> + Method(_OSC, 4) {
> + // Create DWORD-addressable fields from the Capabilities Buffer
> + CreateDWordField(Arg3, 0, CDW1)
> +
> + // Check for proper UUID
> + If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
> + // Create DWORD-addressable fields from the Capabilities Buffer
> + CreateDWordField(Arg3, 4, CDW2)
> + CreateDWordField(Arg3, 8, CDW3)
> +
> + // Save Capabilities DWORD2 & 3
> + Store(CDW2, SUPP)
> + Store(CDW3, CTRL)
> +
> + // Always allow native PME, AER (no dependencies)
> + // Never allow SHPC (no SHPC controller in this system)
> + And(CTRL, 0x1D, CTRL)
> +
> +#if 0 // For now, nothing to do
> + If (Not(And(CDW1, 1))) { // Query flag clear?
> + // Disable GPEs for features granted native control.
> + If (And(CTRL, 0x01)) { // Hot plug control granted?
> + Store(0, HPCE) // clear the hot plug SCI enable bit
> + Store(1, HPCS) // clear the hot plug SCI status bit
> + }
> + If (And(CTRL, 0x04)) { // PME control granted?
> + Store(0, PMCE) // clear the PME SCI enable bit
> + Store(1, PMCS) // clear the PME SCI status bit
> + }
> + If (And(CTRL, 0x10)) { // OS restoring PCI Express cap structure?
> + // Set status to not restore PCI Express cap structure
> + // upon resume from S3
> + Store(1, S3CR)
> + }
> + }
> +#endif
> + If (LNotEqual(Arg1, One)) {
> + // Unknown revision
> + Or(CDW1, 0x08, CDW1)
> + }
> + If (LNotEqual(CDW3, CTRL)) {
> + // Capabilities bits were masked
> + Or(CDW1, 0x10, CDW1)
> + }
> + // Update DWORD3 in the buffer
> + Store(CTRL, CDW3)
> + } Else {
> + Or(CDW1, 4, CDW1) // Unrecognized UUID
> + }
> + Return (Arg3)
> + }
> + }
> + }
> +
> +#include "pci-crs.asl"
> +#include "hpet.asl"
> +
> +
> +/****************************************************************
> + * VGA
> + ****************************************************************/
> +
> + Scope(\_SB.PCI0) {
> + Device(VGA) {
> + Name(_ADR, 0x00010000)
> + Method(_S1D, 0, NotSerialized) {
> + Return (0x00)
> + }
> + Method(_S2D, 0, NotSerialized) {
> + Return (0x00)
> + }
> + Method(_S3D, 0, NotSerialized) {
> + Return (0x00)
> + }
> + }
> + }
> +
> +
> +/****************************************************************
> + * LPC ISA bridge
> + ****************************************************************/
> +
> + Scope(\_SB.PCI0) {
> + /* PCI D31:f0 LPC ISA bridge */
> + Device(ISA) {
> + /* PCI D31:f0 */
> + Name(_ADR, 0x001f0000)
> +
> + /* ICH9 PCI to ISA irq remapping */
> + OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C)
> +
> + OperationRegion(LPCD, PCI_Config, 0x80, 0x2)
> + Field(LPCD, AnyAcc, NoLock, Preserve) {
> + COMA, 3,
> + , 1,
> + COMB, 3,
> +
> + Offset(0x01),
> + LPTD, 2,
> + , 2,
> + FDCD, 2
> + }
> + OperationRegion(LPCE, PCI_Config, 0x82, 0x2)
> + Field(LPCE, AnyAcc, NoLock, Preserve) {
> + CAEN, 1,
> + CBEN, 1,
> + LPEN, 1,
> + FDEN, 1
> + }
> + }
> + }
> +
> +#if 0
> +#include "cpu-hotplug.asl"
> +#endif
> +
> +
> +/****************************************************************
> + * General purpose events
> + ****************************************************************/
> +
> + Scope(\_GPE) {
> + Name(_HID, "ACPI0006")
> +
> + Method(_L00) {
> + }
> + Method(_L01) {
> +#if 0
> + // CPU hotplug event
> + \_SB.PRSC()
> +#endif
> + }
> + Method(_L02) {
> + }
> + Method(_L03) {
> + }
> + Method(_L04) {
> + }
> + Method(_L05) {
> + }
> + Method(_L06) {
> + }
> + Method(_L07) {
> + }
> + Method(_L08) {
> + }
> + Method(_L09) {
> + }
> + Method(_L0A) {
> + }
> + Method(_L0B) {
> + }
> + Method(_L0C) {
> + }
> + Method(_L0D) {
> + }
> + Method(_L0E) {
> + }
> + Method(_L0F) {
> + }
> + }
> +}
> diff --git a/arch/x86/cpu/qemu/hpet.asl b/arch/x86/cpu/qemu/hpet.asl
> new file mode 100644
> index 0000000..f33e527
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/hpet.asl
> @@ -0,0 +1,36 @@
> +/****************************************************************
> + * HPET
> + ****************************************************************/
> +
> +Scope(\_SB) {
> + Device(HPET) {
> + Name(_HID, EISAID("PNP0103"))
> + Name(_UID, 0)
> + OperationRegion(HPTM, SystemMemory, 0xFED00000, 0x400)
> + Field(HPTM, DWordAcc, Lock, Preserve) {
> + VEND, 32,
> + PRD, 32,
> + }
> + Method(_STA, 0, NotSerialized) {
> + Store(VEND, Local0)
> + Store(PRD, Local1)
> + ShiftRight(Local0, 16, Local0)
> + If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) {
> + Return (0x0)
> + }
> + If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) {
> + Return (0x0)
> + }
> + Return (0x0F)
> + }
> + Name(_CRS, ResourceTemplate() {
> +#if 0 /* This makes WinXP BSOD for not yet figured reasons. */
> + IRQNoFlags() {2, 8}
> +#endif
> + Memory32Fixed(ReadOnly,
> + 0xFED00000, // Address Base
> + 0x00000400, // Address Length
> + )
> + })
> + }
> +}
> diff --git a/arch/x86/cpu/qemu/pci-crs.asl b/arch/x86/cpu/qemu/pci-crs.asl
> new file mode 100644
> index 0000000..63d1fd5
> --- /dev/null
> +++ b/arch/x86/cpu/qemu/pci-crs.asl
> @@ -0,0 +1,94 @@
> +/* PCI CRS (current resources) definition. */
> +Scope(\_SB.PCI0) {
> +
> + Name(CRES, ResourceTemplate() {
> + WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
> + 0x0000, // Address Space Granularity
> + 0x0000, // Address Range Minimum
> + 0x00FF, // Address Range Maximum
> + 0x0000, // Address Translation Offset
> + 0x0100, // Address Length
> + ,, )
> + IO(Decode16,
> + 0x0CF8, // Address Range Minimum
> + 0x0CF8, // Address Range Maximum
> + 0x01, // Address Alignment
> + 0x08, // Address Length
> + )
> + WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
> + 0x0000, // Address Space Granularity
> + 0x0000, // Address Range Minimum
> + 0x0CF7, // Address Range Maximum
> + 0x0000, // Address Translation Offset
> + 0x0CF8, // Address Length
> + ,, , TypeStatic)
> + WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
> + 0x0000, // Address Space Granularity
> + 0x0D00, // Address Range Minimum
> + 0xFFFF, // Address Range Maximum
> + 0x0000, // Address Translation Offset
> + 0xF300, // Address Length
> + ,, , TypeStatic)
> + DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
> + 0x00000000, // Address Space Granularity
> + 0x000A0000, // Address Range Minimum
> + 0x000BFFFF, // Address Range Maximum
> + 0x00000000, // Address Translation Offset
> + 0x00020000, // Address Length
> + ,, , AddressRangeMemory, TypeStatic)
> + DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
> + 0x00000000, // Address Space Granularity
> + 0xE0000000, // Address Range Minimum
> + 0xFEBFFFFF, // Address Range Maximum
> + 0x00000000, // Address Translation Offset
> + 0x1EC00000, // Address Length
> + ,, PW32, AddressRangeMemory, TypeStatic)
> + })
> +
> + Name(CR64, ResourceTemplate() {
> + QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
> + 0x00000000, // Address Space Granularity
> + 0x8000000000, // Address Range Minimum
> + 0xFFFFFFFFFF, // Address Range Maximum
> + 0x00000000, // Address Translation Offset
> + 0x8000000000, // Address Length
> + ,, PW64, AddressRangeMemory, TypeStatic)
> + })
> +
> + Method(_CRS, 0) {
> +#if 0
> + /* Fields provided by dynamically created ssdt */
> + External(P0S, IntObj)
> + External(P0E, IntObj)
> + External(P1V, IntObj)
> + External(P1S, BuffObj)
> + External(P1E, BuffObj)
> + External(P1L, BuffObj)
> +
> + /* fixup 32bit pci io window */
> + CreateDWordField(CRES, \_SB.PCI0.PW32._MIN, PS32)
> + CreateDWordField(CRES, \_SB.PCI0.PW32._MAX, PE32)
> + CreateDWordField(CRES, \_SB.PCI0.PW32._LEN, PL32)
> + Store(P0S, PS32)
> + Store(P0E, PE32)
> + Store(Add(Subtract(P0E, P0S), 1), PL32)
> +
> + If (LEqual(P1V, Zero)) {
> + Return (CRES)
> + }
> +
> + /* fixup 64bit pci io window */
> + CreateQWordField(CR64, \_SB.PCI0.PW64._MIN, PS64)
> + CreateQWordField(CR64, \_SB.PCI0.PW64._MAX, PE64)
> + CreateQWordField(CR64, \_SB.PCI0.PW64._LEN, PL64)
> + Store(P1S, PS64)
> + Store(P1E, PE64)
> + Store(P1L, PL64)
> + /* add window and return result */
> + ConcatenateResTemplate(CRES, CR64, Local0)
> + Return (Local0)
> +#else
> + Return (CRES)
> +#endif
> + }
> +}
> diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
> new file mode 100755
> index 0000000..86f0a5b
> --- /dev/null
> +++ b/arch/x86/include/asm/acpi_table.h
> @@ -0,0 +1,318 @@
> +#include <linux/string.h>
> +#include <malloc.h>
> +#include <common.h>
> +#include <asm/post.h>
> +#include <asm/arch/qemu.h>
> +#include <asm/acpigen.h>
> +
> +#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */
> +#define ACPI_TABLE_CREATOR "COREBOOT" /* Must be exactly 8 bytes long! */
> +#define OEM_ID "CORE " /* Must be exactly 6 bytes long! */
> +#define ASLC "CORE" /* Must be exactly 4 bytes long! */
There are existing macros in <asm/acpi.h>. You may need consolidate
them into one.
> +
> +/* RSDP (Root System Description Pointer) */
> +struct __packed acpi_rsdp {
> + char signature[8]; /* RSDP signature */
> + u8 checksum; /* Checksum of the first 20 bytes */
> + char oem_id[6]; /* OEM ID */
> + u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */
> + u32 rsdt_address; /* Physical address of RSDT (32 bits) */
> + u32 length; /* Total RSDP length (incl. extended part) */
> + u64 xsdt_address; /* Physical address of XSDT (64 bits) */
> + u8 ext_checksum; /* Checksum of the whole table */
> + u8 reserved[3];
> +};
> +/* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
> +
> +#define ACPI_ADDRESS_SPACE_MEMORY 0 /* System memory */
> +#define ACPI_ADDRESS_SPACE_IO 1 /* System I/O */
> +#define ACPI_ADDRESS_SPACE_PCI 2 /* PCI config space */
> +#define ACPI_ADDRESS_SPACE_EC 3 /* Embedded controller */
> +#define ACPI_ADDRESS_SPACE_SMBUS 4 /* SMBus */
> +#define ACPI_ADDRESS_SPACE_PCC 0x0A /* Platform Comm. Channel */
> +#define ACPI_ADDRESS_SPACE_FIXED 0x7f /* Functional fixed hardware */
> +#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */
> +#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */
> +#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */
> +#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */
> +#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */
> +#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */
> +/* 0x80-0xbf: Reserved */
> +/* 0xc0-0xff: OEM defined */
> +
> +/* Access size definitions for Generic address structure */
> +#define ACPI_ACCESS_SIZE_UNDEFINED 0 /* Undefined (legacy reasons) */
> +#define ACPI_ACCESS_SIZE_BYTE_ACCESS 1
> +#define ACPI_ACCESS_SIZE_WORD_ACCESS 2
> +#define ACPI_ACCESS_SIZE_DWORD_ACCESS 3
> +#define ACPI_ACCESS_SIZE_QWORD_ACCESS 4
> +
> +/* Generic ACPI header, provided by (almost) all tables */
> +typedef struct acpi_table_header {
> + char signature[4]; /* ACPI signature (4 ASCII characters) */
> + u32 length; /* Table length in bytes (incl. header) */
> + u8 revision; /* Table version (not ACPI version!) */
> + u8 checksum; /* To make sum of entire table == 0 */
> + char oem_id[6]; /* OEM identification */
> + char oem_table_id[8]; /* OEM table identification */
> + u32 oem_revision; /* OEM revision number */
> + char asl_compiler_id[4]; /* ASL compiler vendor ID */
> + u32 asl_compiler_revision; /* ASL compiler revision number */
> +} __attribute__ ((packed)) acpi_header_t;
> +
> +/* A maximum number of 32 ACPI tables ought to be enough for now. */
> +#define MAX_ACPI_TABLES 32
> +
> +/* RSDT (Root System Description Table) */
> +struct __packed acpi_rsdt {
> + struct acpi_table_header header;
> + u32 entry[MAX_ACPI_TABLES];
> +};
> +
> +/* XSDT (Extended System Description Table) */
> +struct __packed acpi_xsdt {
> + struct acpi_table_header header;
> + u64 entry[MAX_ACPI_TABLES];
> +};
> +
> +/* MCFG (PCI Express MMIO config space BAR description table) */
> +struct __packed acpi_mcfg {
> + struct acpi_table_header header;
> + u8 reserved[8];
> +};
> +
> +struct __packed acpi_mcfg_mmconfig {
> + u32 base_address;
> + u32 base_reserved;
> + u16 pci_segment_group_number;
> + u8 start_bus_number;
> + u8 end_bus_number;
> + u8 reserved[4];
> +};
> +
> +/* MADT (Multiple APIC Description Table) */
> +struct __packed acpi_madt {
> + struct acpi_table_header header;
> + u32 lapic_addr; /* Local APIC address */
> + u32 flags; /* Multiple APIC flags */
> +} __attribute__ ((packed)) acpi_madt_t;
> +
> +enum dev_scope_type {
> + SCOPE_PCI_ENDPOINT = 1,
> + SCOPE_PCI_SUB = 2,
> + SCOPE_IOAPIC = 3,
> + SCOPE_MSI_HPET = 4
> +};
> +
> +typedef struct dev_scope {
> + u8 type;
> + u8 length;
> + u8 reserved[2];
> + u8 enumeration;
> + u8 start_bus;
> + struct {
> + u8 dev;
> + u8 fn;
> + } __attribute__((packed)) path[0];
> +} __attribute__ ((packed)) dev_scope_t;
> +
> +/* MADT: APIC Structure Types */
> +/* TODO: Convert to ALLCAPS. */
> +enum acpi_apic_types {
> + LocalApic = 0, /* Processor local APIC */
> + IOApic = 1, /* I/O APIC */
> + IRQSourceOverride = 2, /* Interrupt source override */
> + NMIType = 3, /* NMI source */
> + LocalApicNMI = 4, /* Local APIC NMI */
> + LApicAddressOverride = 5, /* Local APIC address override */
> + IOSApic = 6, /* I/O SAPIC */
> + LocalSApic = 7, /* Local SAPIC */
> + PlatformIRQSources = 8, /* Platform interrupt sources */
> + Localx2Apic = 9, /* Processor local x2APIC */
> + Localx2ApicNMI = 10, /* Local x2APIC NMI */
> + /* 0x0b-0x7f: Reserved */
> + /* 0x80-0xff: Reserved for OEM use */
Please do not use camel case names.
> +};
> +
> +/* MADT: Processor Local APIC Structure */
> +struct __packed acpi_madt_lapic {
> + u8 type; /* Type (0) */
> + u8 length; /* Length in bytes (8) */
> + u8 processor_id; /* ACPI processor ID */
> + u8 apic_id; /* Local APIC ID */
> + u32 flags; /* Local APIC flags */
> +};
> +
> +/* MADT: Local APIC NMI Structure */
> +struct __packed acpi_madt_lapic_nmi {
> + u8 type; /* Type (4) */
> + u8 length; /* Length in bytes (6) */
> + u8 processor_id; /* ACPI processor ID */
> + u16 flags; /* MPS INTI flags */
> + u8 lint; /* Local APIC LINT# */
> +};
> +
> +/* MADT: I/O APIC Structure */
> +struct __packed acpi_madt_ioapic {
> + u8 type; /* Type (1) */
> + u8 length; /* Length in bytes (12) */
> + u8 ioapic_id; /* I/O APIC ID */
> + u8 reserved;
> + u32 ioapic_addr; /* I/O APIC address */
> + u32 gsi_base; /* Global system interrupt base */
> +};
> +
> +/* MADT: Interrupt Source Override Structure */
> +struct __packed acpi_madt_irqoverride {
> + u8 type; /* Type (2) */
> + u8 length; /* Length in bytes (10) */
> + u8 bus; /* ISA (0) */
> + u8 source; /* Bus-relative int. source (IRQ) */
> + u32 gsirq; /* Global system interrupt */
> + u16 flags; /* MPS INTI flags */
> +};
> +
> +/* FADT (Fixed ACPI Description Table) */
> +struct __packed acpi_fadt {
> + struct acpi_table_header header;
> + u32 firmware_ctrl;
> + u32 dsdt;
> + u8 model;
> + u8 preferred_pm_profile;
> + u16 sci_int;
> + u32 smi_cmd;
> + u8 acpi_enable;
> + u8 acpi_disable;
> + u8 s4bios_req;
> + u8 pstate_cnt;
> + u32 pm1a_evt_blk;
> + u32 pm1b_evt_blk;
> + u32 pm1a_cnt_blk;
> + u32 pm1b_cnt_blk;
> + u32 pm2_cnt_blk;
> + u32 pm_tmr_blk;
> + u32 gpe0_blk;
> + u32 gpe1_blk;
> + u8 pm1_evt_len;
> + u8 pm1_cnt_len;
> + u8 pm2_cnt_len;
> + u8 pm_tmr_len;
> + u8 gpe0_blk_len;
> + u8 gpe1_blk_len;
> + u8 gpe1_base;
> + u8 cst_cnt;
> + u16 p_lvl2_lat;
> + u16 p_lvl3_lat;
> + u16 flush_size;
> + u16 flush_stride;
> + u8 duty_offset;
> + u8 duty_width;
> + u8 day_alrm;
> + u8 mon_alrm;
> + u8 century;
> + u16 iapc_boot_arch;
> + u8 res2;
> + u32 flags;
> + struct acpi_gen_regaddr reset_reg;
> + u8 reset_value;
> + u8 res3;
> + u8 res4;
> + u8 res5;
> + u32 x_firmware_ctl_l;
> + u32 x_firmware_ctl_h;
> + u32 x_dsdt_l;
> + u32 x_dsdt_h;
> + struct acpi_gen_regaddr x_pm1a_evt_blk;
> + struct acpi_gen_regaddr x_pm1b_evt_blk;
> + struct acpi_gen_regaddr x_pm1a_cnt_blk;
> + struct acpi_gen_regaddr x_pm1b_cnt_blk;
> + struct acpi_gen_regaddr x_pm2_cnt_blk;
> + struct acpi_gen_regaddr x_pm_tmr_blk;
> + struct acpi_gen_regaddr x_gpe0_blk;
> + struct acpi_gen_regaddr x_gpe1_blk;
> +};
> +
> +/* FADT TABLE Revision values */
> +#define ACPI_FADT_REV_ACPI_1_0 1
> +#define ACPI_FADT_REV_ACPI_2_0 3
> +#define ACPI_FADT_REV_ACPI_3_0 4
> +#define ACPI_FADT_REV_ACPI_4_0 4
> +#define ACPI_FADT_REV_ACPI_5_0 5
> +
> +/* Flags for p_lvl2_lat and p_lvl3_lat */
> +#define ACPI_FADT_C2_NOT_SUPPORTED 101
> +#define ACPI_FADT_C3_NOT_SUPPORTED 1001
> +
> +/* FADT Feature Flags */
> +#define ACPI_FADT_WBINVD (1 << 0)
> +#define ACPI_FADT_WBINVD_FLUSH (1 << 1)
> +#define ACPI_FADT_C1_SUPPORTED (1 << 2)
> +#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3)
> +#define ACPI_FADT_POWER_BUTTON (1 << 4)
> +#define ACPI_FADT_SLEEP_BUTTON (1 << 5)
> +#define ACPI_FADT_FIXED_RTC (1 << 6)
> +#define ACPI_FADT_S4_RTC_WAKE (1 << 7)
> +#define ACPI_FADT_32BIT_TIMER (1 << 8)
> +#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9)
> +#define ACPI_FADT_RESET_REGISTER (1 << 10)
> +#define ACPI_FADT_SEALED_CASE (1 << 11)
> +#define ACPI_FADT_HEADLESS (1 << 12)
> +#define ACPI_FADT_SLEEP_TYPE (1 << 13)
> +#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14)
> +#define ACPI_FADT_PLATFORM_CLOCK (1 << 15)
> +#define ACPI_FADT_S4_RTC_VALID (1 << 16)
> +#define ACPI_FADT_REMOTE_POWER_ON (1 << 17)
> +#define ACPI_FADT_APIC_CLUSTER (1 << 18)
> +#define ACPI_FADT_APIC_PHYSICAL (1 << 19)
> +/* Bits 20-31: reserved ACPI 3.0 & 4.0 */
> +#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20)
> +#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21)
> +/* bits 22-31: reserved ACPI 5.0 */
> +
> +/* FADT Boot Architecture Flags */
> +#define ACPI_FADT_LEGACY_DEVICES (1 << 0)
> +#define ACPI_FADT_8042 (1 << 1)
> +#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2)
> +#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3)
> +#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4)
> +#define ACPI_FADT_LEGACY_FREE 0x00 /* No legacy devices (including 8042) */
> +
> +/* FADT Preferred Power Management Profile */
> +enum acpi_preferred_pm_profiles {
> + PM_UNSPECIFIED = 0,
> + PM_DESKTOP = 1,
> + PM_MOBILE = 2,
> + PM_WORKSTATION = 3,
> + PM_ENTERPRISE_SERVER = 4,
> + PM_SOHO_SERVER = 5,
> + PM_APPLIANCE_PC = 6,
> + PM_PERFORMANCE_SERVER = 7,
> + PM_TABLET = 8, /* ACPI 5.0 */
> +};
> +
> +/* FACS (Firmware ACPI Control Structure) */
> +struct __packed acpi_facs {
> + char signature[4]; /* "FACS" */
> + u32 length; /* Length in bytes (>= 64) */
> + u32 hardware_signature; /* Hardware signature */
> + u32 firmware_waking_vector; /* Firmware waking vector */
> + u32 global_lock; /* Global lock */
> + u32 flags; /* FACS flags */
> + u32 x_firmware_waking_vector_l; /* X FW waking vector, low */
> + u32 x_firmware_waking_vector_h; /* X FW waking vector, high */
> + u8 version; /* ACPI 4.0: 2 */
> + u8 resv[31]; /* FIXME: 4.0: ospm_flags */
> +};
> +
> +/* FACS flags */
> +#define ACPI_FACS_S4BIOS_F (1 << 0)
> +#define ACPI_FACS_64BIT_WAKE_F (1 << 1)
> +/* Bits 31..2: reserved */
> +
> +/* These can be used by the target port. */
> +u8 acpi_checksum(u8 *table, u32 length);
> +
> +void acpi_add_table(struct acpi_rsdp *rsdp, void *table);
> +
> +unsigned long write_acpi_tables(unsigned long start);
> +
> diff --git a/arch/x86/include/asm/acpigen.h b/arch/x86/include/asm/acpigen.h
> new file mode 100755
> index 0000000..d594543
> --- /dev/null
> +++ b/arch/x86/include/asm/acpigen.h
> @@ -0,0 +1,85 @@
> +#ifndef LIBACPI_H
> +#define LIBACPI_H
> +
> +#include <linux/string.h>
> +#include <malloc.h>
> +#include <common.h>
> +#include <asm/post.h>
> +#include <asm/arch/qemu.h>
> +
> +
> +typedef struct acpi_tstate {
> + u32 percent;
> + u32 power;
> + u32 latency;
> + u32 control;
> + u32 status;
> +} __attribute__ ((packed)) acpi_tstate_t;
> +
> +/* GAS (Generic Address Structure) */
> +typedef struct acpi_gen_regaddr {
> + u8 space_id; /* Address space ID */
> + u8 bit_width; /* Register size in bits */
> + u8 bit_offset; /* Register bit offset */
> + union {
> + u8 resv; /* Reserved in ACPI 2.0 - 2.0b */
> + u8 access_size; /* Access size in ACPI 2.0c/3.0/4.0/5.0 */
> + };
> + u32 addrl; /* Register address, low 32 bits */
> + u32 addrh; /* Register address, high 32 bits */
> +} __attribute__ ((packed)) acpi_addr_t;
> +
> +typedef struct acpi_cstate {
> + u8 ctype;
> + u16 latency;
> + u32 power;
> + acpi_addr_t resource;
> +} __attribute__ ((packed)) acpi_cstate_t;
> +
> +
> +int acpigen_write_len_f(void);
> +void acpigen_patch_len(int len);
> +void acpigen_pop_len(void);
> +void acpigen_set_current(char *curr);
> +char *acpigen_get_current(void);
> +int acpigen_write_package(int nr_el);
> +int acpigen_write_byte(unsigned int data);
> +int acpigen_emit_byte(unsigned char data);
> +int acpigen_emit_stream(const char *data, int size);
> +int acpigen_emit_namestring(const char *namepath);
> +int acpigen_emit_eisaid(const char *eisaid);
> +int acpigen_write_dword(unsigned int data);
> +int acpigen_write_qword(uint64_t data);
> +int acpigen_write_name(const char *name);
> +int acpigen_write_name_dword(const char *name, uint32_t val);
> +int acpigen_write_name_qword(const char *name, uint64_t val);
> +int acpigen_write_name_byte(const char *name, uint8_t val);
> +int acpigen_write_scope(const char *name);
> +int acpigen_write_method(const char *name, int nargs);
> +int acpigen_write_device(const char *name);
> +int acpigen_write_PPC(u8 nr);
> +int acpigen_write_PPC_NVS(void);
> +int acpigen_write_empty_PCT(void);
> +int acpigen_write_empty_PTC(void);
> +int acpigen_write_TPC(const char *gnvs_tpc_limit);
> +int acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, u32 busmLat,
> + u32 control, u32 status);
> +typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } PSD_coord;
> +int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
> +int acpigen_write_CST_package_entry(acpi_cstate_t *cstate);
> +int acpigen_write_CST_package(acpi_cstate_t *entry, int nentries);
> +int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len);
> +int acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list);
> +int acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
> +int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size);
> +int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16);
> +int acpigen_write_register(acpi_addr_t *addr);
> +int acpigen_write_resourcetemplate_header(void);
> +int acpigen_write_resourcetemplate_footer(void);
> +int acpigen_write_mainboard_resource_template(void);
> +int acpigen_write_mainboard_resources(const char *scope, const char *name);
> +int acpigen_write_irq(u16 mask);
> +
What are these acpigen_ functions?
> +int get_cst_entries(acpi_cstate_t **);
> +
> +#endif
> diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
> index 8031201..d8d2552 100644
> --- a/arch/x86/lib/tables.c
> +++ b/arch/x86/lib/tables.c
> @@ -7,6 +7,7 @@
> #include <common.h>
> #include <asm/sfi.h>
> #include <asm/tables.h>
> +#include <asm/acpi_table.h>
>
> u8 table_compute_checksum(void *v, int len)
> {
> @@ -32,4 +33,8 @@ void write_tables(void)
> rom_table_end = write_sfi_table(rom_table_end);
> rom_table_end = ALIGN(rom_table_end, 1024);
> #endif
> +#ifdef CONFIG_GENERATE_ACPI_TABLE
> + rom_table_end = write_acpi_tables(rom_table_end);
To keep consistent naming, write_acpi_table() is better.
> + rom_table_end = ALIGN(rom_table_end, 1024);
> +#endif
> }
> diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig
> index 901cbd7..0053756 100644
> --- a/configs/qemu-x86_defconfig
> +++ b/configs/qemu-x86_defconfig
> @@ -3,6 +3,7 @@ CONFIG_VENDOR_EMULATION=y
> CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx"
> CONFIG_TARGET_QEMU_X86=y
> CONFIG_GENERATE_PIRQ_TABLE=y
> +CONFIG_GENERATE_ACPI_TABLE=y
> CONFIG_CMD_NET=y
> CONFIG_OF_CONTROL=y
> CONFIG_VIDEO_VESA=y
> --
Regards,
Bin
More information about the U-Boot
mailing list