acpi/acpi.c: Split of ACPI table generation into separate files
acpi.c contains architectural specific things like IOAPIC, legacy IRQ,
DMAR, HPET, ... all which require the presence of architectural headers.
Instead of littering the code with #if ENV_X86 move the functions to
different compilation units.
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Change-Id: I5083b26c0d4cc6764b4e3cb0ff586797cae7e3af
Reviewed-on: https://review.coreboot.org/c/coreboot/+/76008
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c
index 53f8e0d..0563c24 100644
--- a/src/acpi/acpi.c
+++ b/src/acpi/acpi.c
@@ -16,23 +16,20 @@
#include <acpi/acpi.h>
#include <acpi/acpi_ivrs.h>
#include <acpi/acpigen.h>
-#include <arch/hpet.h>
-#include <arch/smp/mpspec.h>
#include <cbfs.h>
#include <cbmem.h>
#include <commonlib/helpers.h>
-#include <commonlib/sort.h>
#include <console/console.h>
#include <cpu/cpu.h>
#include <device/mmio.h>
#include <device/pci.h>
-#include <pc80/mc146818rtc.h>
#include <string.h>
#include <types.h>
#include <version.h>
#if ENV_X86
#include <arch/ioapic.h>
+#include <arch/smp/mpspec.h>
#endif
static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp);
@@ -142,109 +139,6 @@
return sizeof(acpi_mcfg_mmconfig_t);
}
-static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
-{
- lapic->type = LOCAL_APIC; /* Local APIC structure */
- lapic->length = sizeof(acpi_madt_lapic_t);
- lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
- lapic->processor_id = cpu;
- lapic->apic_id = apic;
-
- return lapic->length;
-}
-
-static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
-{
- lapic->type = LOCAL_X2APIC; /* Local APIC structure */
- lapic->reserved = 0;
- lapic->length = sizeof(acpi_madt_lx2apic_t);
- lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
- lapic->processor_id = cpu;
- lapic->x2apic_id = apic;
-
- return lapic->length;
-}
-
-unsigned long acpi_create_madt_one_lapic(unsigned long current, u32 index, u32 lapic_id)
-{
- if (lapic_id <= ACPI_MADT_MAX_LAPIC_ID)
- current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, index,
- lapic_id);
- else
- current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current, index,
- lapic_id);
-
- return current;
-}
-
-/* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
-#define MAX_THREAD_ID 1
-/*
- * From ACPI 6.4 spec:
- * "The advent of multi-threaded processors yielded multiple logical processors
- * executing on common processor hardware. ACPI defines logical processors in
- * an identical manner as physical processors. To ensure that non
- * multi-threading aware OSPM implementations realize optimal performance on
- * platforms containing multi-threaded processors, two guidelines should be
- * followed. The first is the same as above, that is, OSPM should initialize
- * processors in the order that they appear in the MADT. The second is that
- * platform firmware should list the first logical processor of each of the
- * individual multi-threaded processors in the MADT before listing any of the
- * second logical processors. This approach should be used for all successive
- * logical processors."
- */
-static unsigned long acpi_create_madt_lapics(unsigned long current)
-{
- struct device *cpu;
- int index, apic_ids[CONFIG_MAX_CPUS] = {0}, num_cpus = 0, sort_start = 0;
- for (unsigned int thread_id = 0; thread_id <= MAX_THREAD_ID; thread_id++) {
- for (cpu = all_devices; cpu; cpu = cpu->next) {
- if (!is_enabled_cpu(cpu))
- continue;
- if (num_cpus >= ARRAY_SIZE(apic_ids))
- break;
- if (cpu->path.apic.thread_id != thread_id)
- continue;
- apic_ids[num_cpus++] = cpu->path.apic.apic_id;
- }
- bubblesort(&apic_ids[sort_start], num_cpus - sort_start, NUM_ASCENDING);
- sort_start = num_cpus;
- }
- for (index = 0; index < num_cpus; index++)
- current = acpi_create_madt_one_lapic(current, index, apic_ids[index]);
-
- return current;
-}
-
-static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
- u32 gsi_base)
-{
- ioapic->type = IO_APIC; /* I/O APIC structure */
- ioapic->length = sizeof(acpi_madt_ioapic_t);
- ioapic->reserved = 0x00;
- ioapic->gsi_base = gsi_base;
- ioapic->ioapic_id = id;
- ioapic->ioapic_addr = addr;
-
- return ioapic->length;
-}
-
-#if ENV_X86
-/* For a system with multiple I/O APICs it's required that the one potentially
- routing i8259 via ExtNMI delivery calls this first to get GSI #0. */
-int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr)
-{
- static u32 gsi_base;
- u32 my_base;
- u8 id = get_ioapic_id((void *)(uintptr_t)addr);
- u8 count = ioapic_get_max_vectors((void *)(uintptr_t)addr);
-
- my_base = gsi_base;
- gsi_base += count;
- return acpi_create_madt_ioapic(ioapic, id, addr, my_base);
-}
-#endif
-
static u16 acpi_sci_int(void)
{
#if ENV_X86
@@ -263,100 +157,6 @@
#endif
}
-static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
- u8 bus, u8 source, u32 gsirq, u16 flags)
-{
- irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
- irqoverride->length = sizeof(acpi_madt_irqoverride_t);
- irqoverride->bus = bus;
- irqoverride->source = source;
- irqoverride->gsirq = gsirq;
- irqoverride->flags = flags;
-
- return irqoverride->length;
-}
-
-static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t *irqoverride)
-{
- u8 gsi, irq, flags;
-
- ioapic_get_sci_pin(&gsi, &irq, &flags);
-
- if (!CONFIG(ACPI_HAVE_PCAT_8259))
- irq = gsi;
-
- irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
- irqoverride->length = sizeof(acpi_madt_irqoverride_t);
- irqoverride->bus = MP_BUS_ISA;
- irqoverride->source = irq;
- irqoverride->gsirq = gsi;
- irqoverride->flags = flags;
-
- return irqoverride->length;
-}
-
-static unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current)
-{
- current += acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t *)current, IO_APIC_ADDR);
-
- current += acpi_create_madt_irqoverride((void *)current, MP_BUS_ISA, 0, 2,
- MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH);
-
- current += acpi_create_madt_sci_override((void *)current);
-
- return current;
-}
-
-static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
- u16 flags, u8 lint)
-{
- lapic_nmi->type = LOCAL_APIC_NMI; /* Local APIC NMI structure */
- lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
- lapic_nmi->flags = flags;
- lapic_nmi->processor_id = cpu;
- lapic_nmi->lint = lint;
-
- return lapic_nmi->length;
-}
-
-static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t *lapic_nmi, u32 cpu,
- u16 flags, u8 lint)
-{
- lapic_nmi->type = LOCAL_X2APIC_NMI; /* Local APIC NMI structure */
- lapic_nmi->length = sizeof(acpi_madt_lx2apic_nmi_t);
- lapic_nmi->flags = flags;
- lapic_nmi->processor_id = cpu;
- lapic_nmi->lint = lint;
- lapic_nmi->reserved[0] = 0;
- lapic_nmi->reserved[1] = 0;
- lapic_nmi->reserved[2] = 0;
-
- return lapic_nmi->length;
-}
-
-unsigned long acpi_create_madt_lapic_nmis(unsigned long current)
-{
- const u16 flags = MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH;
-
- /* 1: LINT1 connect to NMI */
- /* create all subtables for processors */
- current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
- ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS, flags, 1);
-
- if (!CONFIG(XAPIC_ONLY))
- current += acpi_create_madt_lx2apic_nmi((acpi_madt_lx2apic_nmi_t *)current,
- ACPI_MADT_LX2APIC_NMI_ALL_PROCESSORS, flags, 1);
-
- return current;
-}
-
-static unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current)
-{
- current = acpi_create_madt_lapics(current);
- current = acpi_create_madt_lapic_nmis(current);
- return current;
-}
-
static void acpi_create_madt(acpi_header_t *header, void *unused)
{
acpi_madt_t *madt = (acpi_madt_t *)header;
@@ -563,33 +363,6 @@
ssdt->length = current - (unsigned long)ssdt;
}
-int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
-{
- memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
-
- lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
- lapic->length = sizeof(acpi_srat_lapic_t);
- lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
- lapic->proximity_domain_7_0 = node;
- /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
- lapic->apic_id = apic;
-
- return lapic->length;
-}
-
-int acpi_create_srat_x2apic(acpi_srat_x2apic_t *x2apic, u32 node, u32 apic)
-{
- memset((void *)x2apic, 0, sizeof(acpi_srat_x2apic_t));
-
- x2apic->type = 2; /* Processor x2APIC structure */
- x2apic->length = sizeof(acpi_srat_x2apic_t);
- x2apic->flags = (1 << 0); /* Enabled (the use of this structure). */
- x2apic->proximity_domain = node;
- x2apic->x2apic_id = apic;
-
- return x2apic->length;
-}
-
int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek,
u32 flags)
{
@@ -752,186 +525,6 @@
header->checksum = acpi_checksum((void *)hmat, header->length);
}
-void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
- unsigned long (*acpi_fill_dmar)(unsigned long))
-{
- acpi_header_t *header = &(dmar->header);
- unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
-
- memset((void *)dmar, 0, sizeof(acpi_dmar_t));
-
- if (acpi_fill_header(header, "DMAR", DMAR, sizeof(acpi_dmar_t)) != CB_SUCCESS)
- return;
-
- dmar->host_address_width = cpu_phys_address_size() - 1;
- dmar->flags = flags;
-
- current = acpi_fill_dmar(current);
-
- /* (Re)calculate length and checksum. */
- header->length = current - (unsigned long)dmar;
- header->checksum = acpi_checksum((void *)dmar, header->length);
-}
-
-unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
- u16 segment, u64 bar)
-{
- dmar_entry_t *drhd = (dmar_entry_t *)current;
- memset(drhd, 0, sizeof(*drhd));
- drhd->type = DMAR_DRHD;
- drhd->length = sizeof(*drhd); /* will be fixed up later */
- drhd->flags = flags;
- drhd->segment = segment;
- drhd->bar = bar;
-
- return drhd->length;
-}
-
-unsigned long acpi_create_dmar_rmrr(unsigned long current, u16 segment,
- u64 bar, u64 limit)
-{
- dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)current;
- memset(rmrr, 0, sizeof(*rmrr));
- rmrr->type = DMAR_RMRR;
- rmrr->length = sizeof(*rmrr); /* will be fixed up later */
- rmrr->segment = segment;
- rmrr->bar = bar;
- rmrr->limit = limit;
-
- return rmrr->length;
-}
-
-unsigned long acpi_create_dmar_atsr(unsigned long current, u8 flags,
- u16 segment)
-{
- dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)current;
- memset(atsr, 0, sizeof(*atsr));
- atsr->type = DMAR_ATSR;
- atsr->length = sizeof(*atsr); /* will be fixed up later */
- atsr->flags = flags;
- atsr->segment = segment;
-
- return atsr->length;
-}
-
-unsigned long acpi_create_dmar_rhsa(unsigned long current, u64 base_addr,
- u32 proximity_domain)
-{
- dmar_rhsa_entry_t *rhsa = (dmar_rhsa_entry_t *)current;
- memset(rhsa, 0, sizeof(*rhsa));
- rhsa->type = DMAR_RHSA;
- rhsa->length = sizeof(*rhsa);
- rhsa->base_address = base_addr;
- rhsa->proximity_domain = proximity_domain;
-
- return rhsa->length;
-}
-
-unsigned long acpi_create_dmar_andd(unsigned long current, u8 device_number,
- const char *device_name)
-{
- dmar_andd_entry_t *andd = (dmar_andd_entry_t *)current;
- int andd_len = sizeof(dmar_andd_entry_t) + strlen(device_name) + 1;
- memset(andd, 0, andd_len);
- andd->type = DMAR_ANDD;
- andd->length = andd_len;
- andd->device_number = device_number;
- memcpy(&andd->device_name, device_name, strlen(device_name));
-
- return andd->length;
-}
-
-unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags, u16 segment)
-{
- dmar_satc_entry_t *satc = (dmar_satc_entry_t *)current;
- int satc_len = sizeof(dmar_satc_entry_t);
- memset(satc, 0, satc_len);
- satc->type = DMAR_SATC;
- satc->length = satc_len;
- satc->flags = flags;
- satc->segment_number = segment;
-
- return satc->length;
-}
-
-void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
-{
- dmar_entry_t *drhd = (dmar_entry_t *)base;
- drhd->length = current - base;
-}
-
-void acpi_dmar_rmrr_fixup(unsigned long base, unsigned long current)
-{
- dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)base;
- rmrr->length = current - base;
-}
-
-void acpi_dmar_atsr_fixup(unsigned long base, unsigned long current)
-{
- dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)base;
- atsr->length = current - base;
-}
-
-void acpi_dmar_satc_fixup(unsigned long base, unsigned long current)
-{
- dmar_satc_entry_t *satc = (dmar_satc_entry_t *)base;
- satc->length = current - base;
-}
-
-static unsigned long acpi_create_dmar_ds(unsigned long current,
- enum dev_scope_type type, u8 enumeration_id, u8 bus, u8 dev, u8 fn)
-{
- /* we don't support longer paths yet */
- const size_t dev_scope_length = sizeof(dev_scope_t) + 2;
-
- dev_scope_t *ds = (dev_scope_t *)current;
- memset(ds, 0, dev_scope_length);
- ds->type = type;
- ds->length = dev_scope_length;
- ds->enumeration = enumeration_id;
- ds->start_bus = bus;
- ds->path[0].dev = dev;
- ds->path[0].fn = fn;
-
- return ds->length;
-}
-
-unsigned long acpi_create_dmar_ds_pci_br(unsigned long current, u8 bus,
- u8 dev, u8 fn)
-{
- return acpi_create_dmar_ds(current,
- SCOPE_PCI_SUB, 0, bus, dev, fn);
-}
-
-unsigned long acpi_create_dmar_ds_pci(unsigned long current, u8 bus,
- u8 dev, u8 fn)
-{
- return acpi_create_dmar_ds(current,
- SCOPE_PCI_ENDPOINT, 0, bus, dev, fn);
-}
-
-unsigned long acpi_create_dmar_ds_ioapic(unsigned long current,
- u8 enumeration_id, u8 bus, u8 dev, u8 fn)
-{
- return acpi_create_dmar_ds(current,
- SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
-}
-
-unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current,
- u32 addr, u8 bus, u8 dev, u8 fn)
-{
- u8 enumeration_id = get_ioapic_id((void *)(uintptr_t)addr);
- return acpi_create_dmar_ds(current,
- SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
-}
-
-unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current,
- u8 enumeration_id, u8 bus, u8 dev, u8 fn)
-{
- return acpi_create_dmar_ds(current,
- SCOPE_MSI_HPET, enumeration_id, bus, dev, fn);
-}
-
/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
void acpi_create_slit(acpi_slit_t *slit,
unsigned long (*acpi_fill_slit)(unsigned long current))
@@ -951,31 +544,6 @@
header->checksum = acpi_checksum((void *)slit, header->length);
}
-/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */
-static void acpi_create_hpet(acpi_hpet_t *hpet)
-{
- acpi_header_t *header = &(hpet->header);
- acpi_addr_t *addr = &(hpet->addr);
-
- memset((void *)hpet, 0, sizeof(acpi_hpet_t));
-
- if (acpi_fill_header(header, "HPET", HPET, sizeof(acpi_hpet_t)) != CB_SUCCESS)
- return;
-
- /* Fill out HPET address. */
- addr->space_id = ACPI_ADDRESS_SPACE_MEMORY;
- addr->bit_width = 64;
- addr->bit_offset = 0;
- addr->addrl = HPET_BASE_ADDRESS & 0xffffffff;
- addr->addrh = ((unsigned long long)HPET_BASE_ADDRESS) >> 32;
-
- hpet->id = read32p(HPET_BASE_ADDRESS);
- hpet->number = 0;
- hpet->min_tick = CONFIG_HPET_MIN_TICKS;
-
- header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
-}
-
/*
* This method adds the ACPI error injection capability. It fills the default information.
* HW dependent code (caller) can modify the defaults upon return. If no changes are necessary
@@ -1222,25 +790,6 @@
header->checksum = acpi_checksum((void *)crat, header->length);
}
-unsigned long acpi_write_hpet(const struct device *device, unsigned long current,
- acpi_rsdp_t *rsdp)
-{
- acpi_hpet_t *hpet;
-
- /*
- * We explicitly add these tables later on:
- */
- printk(BIOS_DEBUG, "ACPI: * HPET\n");
-
- hpet = (acpi_hpet_t *)current;
- current += sizeof(acpi_hpet_t);
- current = ALIGN_UP(current, 16);
- acpi_create_hpet(hpet);
- acpi_add_table(rsdp, hpet);
-
- return current;
-}
-
static void acpi_create_dbg2(acpi_dbg2_header_t *dbg2,
int port_type, int port_subtype,
acpi_addr_t *address, uint32_t address_size,
diff --git a/src/acpi/acpi_apic.c b/src/acpi/acpi_apic.c
new file mode 100644
index 0000000..38daaab
--- /dev/null
+++ b/src/acpi/acpi_apic.c
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+#include <arch/ioapic.h>
+#include <arch/smp/mpspec.h>
+#include <commonlib/sort.h>
+#include <cpu/cpu.h>
+
+static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
+{
+ lapic->type = LOCAL_APIC; /* Local APIC structure */
+ lapic->length = sizeof(acpi_madt_lapic_t);
+ lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
+ lapic->processor_id = cpu;
+ lapic->apic_id = apic;
+
+ return lapic->length;
+}
+
+static int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
+{
+ lapic->type = LOCAL_X2APIC; /* Local APIC structure */
+ lapic->reserved = 0;
+ lapic->length = sizeof(acpi_madt_lx2apic_t);
+ lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
+ lapic->processor_id = cpu;
+ lapic->x2apic_id = apic;
+
+ return lapic->length;
+}
+
+unsigned long acpi_create_madt_one_lapic(unsigned long current, u32 index, u32 lapic_id)
+{
+ if (lapic_id <= ACPI_MADT_MAX_LAPIC_ID)
+ current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current, index,
+ lapic_id);
+ else
+ current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current, index,
+ lapic_id);
+
+ return current;
+}
+
+/* Increase if necessary. Currently all x86 CPUs only have 2 SMP threads */
+#define MAX_THREAD_ID 1
+/*
+ * From ACPI 6.4 spec:
+ * "The advent of multi-threaded processors yielded multiple logical processors
+ * executing on common processor hardware. ACPI defines logical processors in
+ * an identical manner as physical processors. To ensure that non
+ * multi-threading aware OSPM implementations realize optimal performance on
+ * platforms containing multi-threaded processors, two guidelines should be
+ * followed. The first is the same as above, that is, OSPM should initialize
+ * processors in the order that they appear in the MADT. The second is that
+ * platform firmware should list the first logical processor of each of the
+ * individual multi-threaded processors in the MADT before listing any of the
+ * second logical processors. This approach should be used for all successive
+ * logical processors."
+ */
+static unsigned long acpi_create_madt_lapics(unsigned long current)
+{
+ struct device *cpu;
+ int index, apic_ids[CONFIG_MAX_CPUS] = {0}, num_cpus = 0, sort_start = 0;
+ for (unsigned int thread_id = 0; thread_id <= MAX_THREAD_ID; thread_id++) {
+ for (cpu = all_devices; cpu; cpu = cpu->next) {
+ if (!is_enabled_cpu(cpu))
+ continue;
+ if (num_cpus >= ARRAY_SIZE(apic_ids))
+ break;
+ if (cpu->path.apic.thread_id != thread_id)
+ continue;
+ apic_ids[num_cpus++] = cpu->path.apic.apic_id;
+ }
+ bubblesort(&apic_ids[sort_start], num_cpus - sort_start, NUM_ASCENDING);
+ sort_start = num_cpus;
+ }
+ for (index = 0; index < num_cpus; index++)
+ current = acpi_create_madt_one_lapic(current, index, apic_ids[index]);
+
+ return current;
+}
+
+static int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
+ u32 gsi_base)
+{
+ ioapic->type = IO_APIC; /* I/O APIC structure */
+ ioapic->length = sizeof(acpi_madt_ioapic_t);
+ ioapic->reserved = 0x00;
+ ioapic->gsi_base = gsi_base;
+ ioapic->ioapic_id = id;
+ ioapic->ioapic_addr = addr;
+
+ return ioapic->length;
+}
+
+/* For a system with multiple I/O APICs it's required that the one potentially
+ routing i8259 via ExtNMI delivery calls this first to get GSI #0. */
+int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr)
+{
+ static u32 gsi_base;
+ u32 my_base;
+ u8 id = get_ioapic_id((void *)(uintptr_t)addr);
+ u8 count = ioapic_get_max_vectors((void *)(uintptr_t)addr);
+
+ my_base = gsi_base;
+ gsi_base += count;
+ return acpi_create_madt_ioapic(ioapic, id, addr, my_base);
+}
+
+static int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
+ u8 bus, u8 source, u32 gsirq, u16 flags)
+{
+ irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
+ irqoverride->length = sizeof(acpi_madt_irqoverride_t);
+ irqoverride->bus = bus;
+ irqoverride->source = source;
+ irqoverride->gsirq = gsirq;
+ irqoverride->flags = flags;
+
+ return irqoverride->length;
+}
+
+static int acpi_create_madt_sci_override(acpi_madt_irqoverride_t *irqoverride)
+{
+ u8 gsi, irq, flags;
+
+ ioapic_get_sci_pin(&gsi, &irq, &flags);
+
+ if (!CONFIG(ACPI_HAVE_PCAT_8259))
+ irq = gsi;
+
+ irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
+ irqoverride->length = sizeof(acpi_madt_irqoverride_t);
+ irqoverride->bus = MP_BUS_ISA;
+ irqoverride->source = irq;
+ irqoverride->gsirq = gsi;
+ irqoverride->flags = flags;
+
+ return irqoverride->length;
+}
+
+unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current)
+{
+ current += acpi_create_madt_ioapic_from_hw((acpi_madt_ioapic_t *)current, IO_APIC_ADDR);
+
+ current += acpi_create_madt_irqoverride((void *)current, MP_BUS_ISA, 0, 2,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH);
+
+ current += acpi_create_madt_sci_override((void *)current);
+
+ return current;
+}
+
+static int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
+ u16 flags, u8 lint)
+{
+ lapic_nmi->type = LOCAL_APIC_NMI; /* Local APIC NMI structure */
+ lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
+ lapic_nmi->flags = flags;
+ lapic_nmi->processor_id = cpu;
+ lapic_nmi->lint = lint;
+
+ return lapic_nmi->length;
+}
+
+static int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t *lapic_nmi, u32 cpu,
+ u16 flags, u8 lint)
+{
+ lapic_nmi->type = LOCAL_X2APIC_NMI; /* Local APIC NMI structure */
+ lapic_nmi->length = sizeof(acpi_madt_lx2apic_nmi_t);
+ lapic_nmi->flags = flags;
+ lapic_nmi->processor_id = cpu;
+ lapic_nmi->lint = lint;
+ lapic_nmi->reserved[0] = 0;
+ lapic_nmi->reserved[1] = 0;
+ lapic_nmi->reserved[2] = 0;
+
+ return lapic_nmi->length;
+}
+
+unsigned long acpi_create_madt_lapic_nmis(unsigned long current)
+{
+ const u16 flags = MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH;
+
+ /* 1: LINT1 connect to NMI */
+ /* create all subtables for processors */
+ current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
+ ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS, flags, 1);
+
+ if (!CONFIG(XAPIC_ONLY))
+ current += acpi_create_madt_lx2apic_nmi((acpi_madt_lx2apic_nmi_t *)current,
+ ACPI_MADT_LX2APIC_NMI_ALL_PROCESSORS, flags, 1);
+
+ return current;
+}
+
+unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current)
+{
+ current = acpi_create_madt_lapics(current);
+ current = acpi_create_madt_lapic_nmis(current);
+ return current;
+}
+
+int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
+{
+ memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
+
+ lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
+ lapic->length = sizeof(acpi_srat_lapic_t);
+ lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
+ lapic->proximity_domain_7_0 = node;
+ /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
+ lapic->apic_id = apic;
+
+ return lapic->length;
+}
+
+int acpi_create_srat_x2apic(acpi_srat_x2apic_t *x2apic, u32 node, u32 apic)
+{
+ memset((void *)x2apic, 0, sizeof(acpi_srat_x2apic_t));
+
+ x2apic->type = 2; /* Processor x2APIC structure */
+ x2apic->length = sizeof(acpi_srat_x2apic_t);
+ x2apic->flags = (1 << 0); /* Enabled (the use of this structure). */
+ x2apic->proximity_domain = node;
+ x2apic->x2apic_id = apic;
+
+ return x2apic->length;
+}
diff --git a/src/acpi/acpi_dmar.c b/src/acpi/acpi_dmar.c
new file mode 100644
index 0000000..83a876c
--- /dev/null
+++ b/src/acpi/acpi_dmar.c
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+#include <arch/ioapic.h>
+#include <cpu/cpu.h>
+#include <version.h>
+
+void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
+ unsigned long (*acpi_fill_dmar)(unsigned long))
+{
+ acpi_header_t *header = &(dmar->header);
+ unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
+
+ memset((void *)dmar, 0, sizeof(acpi_dmar_t));
+
+ if (!header)
+ return;
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "DMAR", 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->asl_compiler_revision = asl_revision;
+ header->length = sizeof(acpi_dmar_t);
+ header->revision = get_acpi_table_revision(DMAR);
+
+ dmar->host_address_width = cpu_phys_address_size() - 1;
+ dmar->flags = flags;
+
+ current = acpi_fill_dmar(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)dmar;
+ header->checksum = acpi_checksum((void *)dmar, header->length);
+}
+
+unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
+ u16 segment, u64 bar)
+{
+ dmar_entry_t *drhd = (dmar_entry_t *)current;
+ memset(drhd, 0, sizeof(*drhd));
+ drhd->type = DMAR_DRHD;
+ drhd->length = sizeof(*drhd); /* will be fixed up later */
+ drhd->flags = flags;
+ drhd->segment = segment;
+ drhd->bar = bar;
+
+ return drhd->length;
+}
+
+unsigned long acpi_create_dmar_rmrr(unsigned long current, u16 segment,
+ u64 bar, u64 limit)
+{
+ dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)current;
+ memset(rmrr, 0, sizeof(*rmrr));
+ rmrr->type = DMAR_RMRR;
+ rmrr->length = sizeof(*rmrr); /* will be fixed up later */
+ rmrr->segment = segment;
+ rmrr->bar = bar;
+ rmrr->limit = limit;
+
+ return rmrr->length;
+}
+
+unsigned long acpi_create_dmar_atsr(unsigned long current, u8 flags,
+ u16 segment)
+{
+ dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)current;
+ memset(atsr, 0, sizeof(*atsr));
+ atsr->type = DMAR_ATSR;
+ atsr->length = sizeof(*atsr); /* will be fixed up later */
+ atsr->flags = flags;
+ atsr->segment = segment;
+
+ return atsr->length;
+}
+
+unsigned long acpi_create_dmar_rhsa(unsigned long current, u64 base_addr,
+ u32 proximity_domain)
+{
+ dmar_rhsa_entry_t *rhsa = (dmar_rhsa_entry_t *)current;
+ memset(rhsa, 0, sizeof(*rhsa));
+ rhsa->type = DMAR_RHSA;
+ rhsa->length = sizeof(*rhsa);
+ rhsa->base_address = base_addr;
+ rhsa->proximity_domain = proximity_domain;
+
+ return rhsa->length;
+}
+
+unsigned long acpi_create_dmar_andd(unsigned long current, u8 device_number,
+ const char *device_name)
+{
+ dmar_andd_entry_t *andd = (dmar_andd_entry_t *)current;
+ int andd_len = sizeof(dmar_andd_entry_t) + strlen(device_name) + 1;
+ memset(andd, 0, andd_len);
+ andd->type = DMAR_ANDD;
+ andd->length = andd_len;
+ andd->device_number = device_number;
+ memcpy(&andd->device_name, device_name, strlen(device_name));
+
+ return andd->length;
+}
+
+unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags, u16 segment)
+{
+ dmar_satc_entry_t *satc = (dmar_satc_entry_t *)current;
+ int satc_len = sizeof(dmar_satc_entry_t);
+ memset(satc, 0, satc_len);
+ satc->type = DMAR_SATC;
+ satc->length = satc_len;
+ satc->flags = flags;
+ satc->segment_number = segment;
+
+ return satc->length;
+}
+
+void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
+{
+ dmar_entry_t *drhd = (dmar_entry_t *)base;
+ drhd->length = current - base;
+}
+
+void acpi_dmar_rmrr_fixup(unsigned long base, unsigned long current)
+{
+ dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)base;
+ rmrr->length = current - base;
+}
+
+void acpi_dmar_atsr_fixup(unsigned long base, unsigned long current)
+{
+ dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)base;
+ atsr->length = current - base;
+}
+
+void acpi_dmar_satc_fixup(unsigned long base, unsigned long current)
+{
+ dmar_satc_entry_t *satc = (dmar_satc_entry_t *)base;
+ satc->length = current - base;
+}
+
+static unsigned long acpi_create_dmar_ds(unsigned long current,
+ enum dev_scope_type type, u8 enumeration_id, u8 bus, u8 dev, u8 fn)
+{
+ /* we don't support longer paths yet */
+ const size_t dev_scope_length = sizeof(dev_scope_t) + 2;
+
+ dev_scope_t *ds = (dev_scope_t *)current;
+ memset(ds, 0, dev_scope_length);
+ ds->type = type;
+ ds->length = dev_scope_length;
+ ds->enumeration = enumeration_id;
+ ds->start_bus = bus;
+ ds->path[0].dev = dev;
+ ds->path[0].fn = fn;
+
+ return ds->length;
+}
+
+unsigned long acpi_create_dmar_ds_pci_br(unsigned long current, u8 bus,
+ u8 dev, u8 fn)
+{
+ return acpi_create_dmar_ds(current,
+ SCOPE_PCI_SUB, 0, bus, dev, fn);
+}
+
+unsigned long acpi_create_dmar_ds_pci(unsigned long current, u8 bus,
+ u8 dev, u8 fn)
+{
+ return acpi_create_dmar_ds(current,
+ SCOPE_PCI_ENDPOINT, 0, bus, dev, fn);
+}
+
+unsigned long acpi_create_dmar_ds_ioapic(unsigned long current,
+ u8 enumeration_id, u8 bus, u8 dev, u8 fn)
+{
+ return acpi_create_dmar_ds(current,
+ SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
+}
+
+unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current,
+ u32 addr, u8 bus, u8 dev, u8 fn)
+{
+ u8 enumeration_id = get_ioapic_id((void *)(uintptr_t)addr);
+ return acpi_create_dmar_ds(current,
+ SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
+}
+
+unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current,
+ u8 enumeration_id, u8 bus, u8 dev, u8 fn)
+{
+ return acpi_create_dmar_ds(current,
+ SCOPE_MSI_HPET, enumeration_id, bus, dev, fn);
+}
diff --git a/src/acpi/acpi_hpet.c b/src/acpi/acpi_hpet.c
new file mode 100644
index 0000000..9f91829
--- /dev/null
+++ b/src/acpi/acpi_hpet.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+#include <arch/hpet.h>
+#include <console/console.h>
+#include <device/mmio.h>
+#include <version.h>
+
+
+/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */
+static void acpi_create_hpet(acpi_hpet_t *hpet)
+{
+ acpi_header_t *header = &(hpet->header);
+ acpi_addr_t *addr = &(hpet->addr);
+
+ memset((void *)hpet, 0, sizeof(acpi_hpet_t));
+
+ if (!header)
+ return;
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "HPET", 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->asl_compiler_revision = asl_revision;
+ header->length = sizeof(acpi_hpet_t);
+ header->revision = get_acpi_table_revision(HPET);
+
+ /* Fill out HPET address. */
+ addr->space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ addr->bit_width = 64;
+ addr->bit_offset = 0;
+ addr->addrl = HPET_BASE_ADDRESS & 0xffffffff;
+ addr->addrh = ((unsigned long long)HPET_BASE_ADDRESS) >> 32;
+
+ hpet->id = read32p(HPET_BASE_ADDRESS);
+ hpet->number = 0;
+ hpet->min_tick = CONFIG_HPET_MIN_TICKS;
+
+ header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
+}
+
+unsigned long acpi_write_hpet(const struct device *device, unsigned long current,
+ acpi_rsdp_t *rsdp)
+{
+ acpi_hpet_t *hpet;
+
+ /*
+ * We explicitly add these tables later on:
+ */
+ printk(BIOS_DEBUG, "ACPI: * HPET\n");
+
+ hpet = (acpi_hpet_t *)current;
+ current += sizeof(acpi_hpet_t);
+ current = ALIGN_UP(current, 16);
+ acpi_create_hpet(hpet);
+ acpi_add_table(rsdp, hpet);
+
+ return current;
+}
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
index ab365fe..e0e8a3b 100644
--- a/src/arch/x86/Makefile.inc
+++ b/src/arch/x86/Makefile.inc
@@ -253,6 +253,7 @@
ifeq ($(CONFIG_ARCH_RAMSTAGE_X86_32)$(CONFIG_ARCH_RAMSTAGE_X86_64),y)
ramstage-y += acpi.c
+ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ../../acpi/acpi_apic.c ../../acpi/acpi_hpet.c ../../acpi/acpi_dmar.c
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.c
ramstage-$(CONFIG_ACPI_BERT) += acpi_bert_storage.c
ramstage-y += boot.c
diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h
index 60efbdb..dc26b85 100644
--- a/src/include/acpi/acpi.h
+++ b/src/include/acpi/acpi.h
@@ -1468,10 +1468,13 @@
int acpi_create_cedt_cfmws(acpi_cedt_cfmws_t *cfmws, u64 base_hpa, u64 window_size,
u8 eniw, u32 hbig, u16 restriction, u16 qtg_id, const u32 *interleave_target);
+
+unsigned long acpi_create_madt_ioapic_gsi0_default(unsigned long current);
int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr);
unsigned long acpi_create_madt_one_lapic(unsigned long current, u32 cpu, u32 apic);
+unsigned long acpi_create_madt_lapics_with_nmis(unsigned long current);
unsigned long acpi_create_madt_lapic_nmis(unsigned long current);
int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic);