2019-05-27 14:55:06 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* acpi_tables.c - ACPI Boot-Time Table Parsing
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
|
|
|
*/
|
|
|
|
|
2015-03-24 22:02:34 +08:00
|
|
|
/* Uncomment next line to get verbose printout */
|
|
|
|
/* #define DEBUG */
|
2014-02-20 15:45:33 +08:00
|
|
|
#define pr_fmt(fmt) "ACPI: " fmt
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/smp.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/irq.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/acpi.h>
|
2016-04-11 10:13:18 +08:00
|
|
|
#include <linux/memblock.h>
|
2018-10-31 06:09:49 +08:00
|
|
|
#include <linux/earlycpio.h>
|
2016-06-20 18:56:10 +08:00
|
|
|
#include <linux/initrd.h>
|
2019-08-20 08:17:52 +08:00
|
|
|
#include <linux/security.h>
|
2021-10-21 15:09:29 +08:00
|
|
|
#include <linux/kmemleak.h>
|
2016-03-02 14:16:25 +08:00
|
|
|
#include "internal.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-05-06 07:27:09 +08:00
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
|
|
|
#include CONFIG_ACPI_CUSTOM_DSDT_FILE
|
|
|
|
#endif
|
|
|
|
|
2005-12-30 15:44:59 +08:00
|
|
|
#define ACPI_MAX_TABLES 128
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
|
|
|
|
static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
|
|
|
|
|
2007-02-03 00:48:19 +08:00
|
|
|
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2021-10-30 03:51:32 +08:00
|
|
|
static int acpi_apic_instance __initdata_or_acpilib;
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2014-05-31 08:15:02 +08:00
|
|
|
/*
|
|
|
|
* Disable table checksum verification for the early stage due to the size
|
|
|
|
* limitation of the current x86 early mapping implementation.
|
|
|
|
*/
|
2021-10-30 03:51:32 +08:00
|
|
|
static bool acpi_verify_table_checksum __initdata_or_acpilib = false;
|
2014-05-31 08:15:02 +08:00
|
|
|
|
2007-03-11 15:26:14 +08:00
|
|
|
void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (header->type) {
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_LOCAL_APIC:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_local_apic *p =
|
|
|
|
(struct acpi_madt_local_apic *)header;
|
2015-03-24 22:02:34 +08:00
|
|
|
pr_debug("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
|
|
|
|
p->processor_id, p->id,
|
|
|
|
(p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2009-03-31 05:55:30 +08:00
|
|
|
case ACPI_MADT_TYPE_LOCAL_X2APIC:
|
|
|
|
{
|
|
|
|
struct acpi_madt_local_x2apic *p =
|
|
|
|
(struct acpi_madt_local_x2apic *)header;
|
2015-03-24 22:02:34 +08:00
|
|
|
pr_debug("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
|
|
|
|
p->local_apic_id, p->uid,
|
|
|
|
(p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
2009-03-31 05:55:30 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_IO_APIC:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_io_apic *p =
|
|
|
|
(struct acpi_madt_io_apic *)header;
|
2015-03-24 22:02:34 +08:00
|
|
|
pr_debug("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
|
|
|
|
p->id, p->address, p->global_irq_base);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_interrupt_override *p =
|
|
|
|
(struct acpi_madt_interrupt_override *)header;
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
|
|
|
|
p->bus, p->source_irq, p->global_irq,
|
|
|
|
mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
|
|
|
|
mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
|
2007-02-03 00:48:22 +08:00
|
|
|
if (p->inti_flags &
|
|
|
|
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
|
|
|
|
p->inti_flags &
|
2007-02-03 00:48:22 +08:00
|
|
|
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_NMI_SOURCE:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_nmi_source *p =
|
|
|
|
(struct acpi_madt_nmi_source *)header;
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("NMI_SRC (%s %s global_irq %d)\n",
|
|
|
|
mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
|
|
|
|
mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
|
|
|
|
p->global_irq);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_local_apic_nmi *p =
|
|
|
|
(struct acpi_madt_local_apic_nmi *)header;
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
|
|
|
|
p->processor_id,
|
|
|
|
mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
|
|
|
|
mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
|
|
|
|
p->lint);
|
2009-03-31 05:55:30 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
|
|
|
|
{
|
|
|
|
u16 polarity, trigger;
|
|
|
|
struct acpi_madt_local_x2apic_nmi *p =
|
|
|
|
(struct acpi_madt_local_x2apic_nmi *)header;
|
|
|
|
|
|
|
|
polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
|
|
|
|
trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
|
|
|
|
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
|
|
|
|
p->uid,
|
|
|
|
mps_inti_flags_polarity[polarity],
|
|
|
|
mps_inti_flags_trigger[trigger],
|
|
|
|
p->lint);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_local_apic_override *p =
|
|
|
|
(struct acpi_madt_local_apic_override *)header;
|
2022-03-17 14:42:20 +08:00
|
|
|
pr_info("LAPIC_ADDR_OVR (address[0x%llx])\n",
|
|
|
|
p->address);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_IO_SAPIC:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_io_sapic *p =
|
|
|
|
(struct acpi_madt_io_sapic *)header;
|
2015-03-24 22:02:34 +08:00
|
|
|
pr_debug("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
|
|
|
|
p->id, (void *)(unsigned long)p->address,
|
|
|
|
p->global_irq_base);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_LOCAL_SAPIC:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_local_sapic *p =
|
|
|
|
(struct acpi_madt_local_sapic *)header;
|
2015-03-24 22:02:34 +08:00
|
|
|
pr_debug("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
|
|
|
|
p->processor_id, p->id, p->eid,
|
|
|
|
(p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
|
2005-08-05 12:44:28 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_madt_interrupt_source *p =
|
|
|
|
(struct acpi_madt_interrupt_source *)header;
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
|
|
|
|
mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
|
|
|
|
mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
|
|
|
|
p->type, p->id, p->eid, p->io_sapic_vector,
|
|
|
|
p->global_irq);
|
2005-08-05 12:44:28 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2015-03-24 22:02:44 +08:00
|
|
|
case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
|
|
|
|
{
|
|
|
|
struct acpi_madt_generic_interrupt *p =
|
|
|
|
(struct acpi_madt_generic_interrupt *)header;
|
|
|
|
pr_debug("GICC (acpi_id[0x%04x] address[%llx] MPIDR[0x%llx] %s)\n",
|
|
|
|
p->uid, p->base_address,
|
|
|
|
p->arm_mpidr,
|
|
|
|
(p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
|
|
|
|
{
|
|
|
|
struct acpi_madt_generic_distributor *p =
|
|
|
|
(struct acpi_madt_generic_distributor *)header;
|
|
|
|
pr_debug("GIC Distributor (gic_id[0x%04x] address[%llx] gsi_base[%d])\n",
|
|
|
|
p->gic_id, p->base_address,
|
|
|
|
p->global_irq_base);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2024-06-14 17:59:04 +08:00
|
|
|
case ACPI_MADT_TYPE_MULTIPROC_WAKEUP:
|
|
|
|
{
|
|
|
|
struct acpi_madt_multiproc_wakeup *p =
|
|
|
|
(struct acpi_madt_multiproc_wakeup *)header;
|
|
|
|
u64 reset_vector = 0;
|
|
|
|
|
|
|
|
if (p->version >= ACPI_MADT_MP_WAKEUP_VERSION_V1)
|
|
|
|
reset_vector = p->reset_vector;
|
|
|
|
|
|
|
|
pr_debug("MP Wakeup (version[%d], mailbox[%#llx], reset[%#llx])\n",
|
|
|
|
p->version, p->mailbox_address, reset_vector);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-11-02 14:48:38 +08:00
|
|
|
case ACPI_MADT_TYPE_CORE_PIC:
|
|
|
|
{
|
|
|
|
struct acpi_madt_core_pic *p = (struct acpi_madt_core_pic *)header;
|
|
|
|
|
|
|
|
pr_debug("CORE PIC (processor_id[0x%02x] core_id[0x%02x] %s)\n",
|
|
|
|
p->processor_id, p->core_id,
|
|
|
|
(p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2023-05-15 13:49:11 +08:00
|
|
|
case ACPI_MADT_TYPE_RINTC:
|
|
|
|
{
|
|
|
|
struct acpi_madt_rintc *p = (struct acpi_madt_rintc *)header;
|
|
|
|
|
|
|
|
pr_debug("RISC-V INTC (acpi_uid[0x%04x] hart_id[0x%llx] %s)\n",
|
|
|
|
p->uid, p->hart_id,
|
|
|
|
(p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
|
|
|
|
header->type);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-30 03:51:32 +08:00
|
|
|
int __init_or_acpilib acpi_table_parse_entries_array(
|
|
|
|
char *id, unsigned long table_size, struct acpi_subtable_proc *proc,
|
|
|
|
int proc_num, unsigned int max_entries)
|
2014-11-26 22:01:13 +08:00
|
|
|
{
|
|
|
|
struct acpi_table_header *table_header = NULL;
|
|
|
|
int count;
|
|
|
|
u32 instance = 0;
|
|
|
|
|
|
|
|
if (acpi_disabled)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2015-09-09 21:47:28 +08:00
|
|
|
if (!id)
|
2014-11-26 22:01:13 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-21 17:59:04 +08:00
|
|
|
if (!table_size)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-11-26 22:01:13 +08:00
|
|
|
if (!strncmp(id, ACPI_SIG_MADT, 4))
|
|
|
|
instance = acpi_apic_instance;
|
|
|
|
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_get_table(id, instance, &table_header);
|
2014-11-26 22:01:13 +08:00
|
|
|
if (!table_header) {
|
2022-02-16 02:54:23 +08:00
|
|
|
pr_debug("%4.4s not present\n", id);
|
2014-11-26 22:01:13 +08:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2023-12-22 06:02:31 +08:00
|
|
|
count = acpi_parse_entries_array(id, table_size,
|
|
|
|
(union fw_table_header *)table_header,
|
2024-02-18 05:39:46 +08:00
|
|
|
0, proc, proc_num, max_entries);
|
2014-11-26 22:01:13 +08:00
|
|
|
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_put_table(table_header);
|
2014-11-26 22:01:13 +08:00
|
|
|
return count;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 03:51:42 +08:00
|
|
|
static int __init_or_acpilib __acpi_table_parse_entries(
|
|
|
|
char *id, unsigned long table_size, int entry_id,
|
|
|
|
acpi_tbl_entry_handler handler, acpi_tbl_entry_handler_arg handler_arg,
|
|
|
|
void *arg, unsigned int max_entries)
|
2015-09-09 21:47:28 +08:00
|
|
|
{
|
|
|
|
struct acpi_subtable_proc proc = {
|
|
|
|
.id = entry_id,
|
|
|
|
.handler = handler,
|
2021-10-30 03:51:42 +08:00
|
|
|
.handler_arg = handler_arg,
|
|
|
|
.arg = arg,
|
2015-09-09 21:47:28 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
return acpi_table_parse_entries_array(id, table_size, &proc, 1,
|
|
|
|
max_entries);
|
|
|
|
}
|
|
|
|
|
2021-10-30 03:51:42 +08:00
|
|
|
int __init_or_acpilib
|
|
|
|
acpi_table_parse_cedt(enum acpi_cedt_type id,
|
|
|
|
acpi_tbl_entry_handler_arg handler_arg, void *arg)
|
|
|
|
{
|
|
|
|
return __acpi_table_parse_entries(ACPI_SIG_CEDT,
|
|
|
|
sizeof(struct acpi_table_cedt), id,
|
|
|
|
NULL, handler_arg, arg, 0);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_ACPI_LIB(acpi_table_parse_cedt);
|
|
|
|
|
|
|
|
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
|
|
|
|
int entry_id,
|
|
|
|
acpi_tbl_entry_handler handler,
|
|
|
|
unsigned int max_entries)
|
|
|
|
{
|
|
|
|
return __acpi_table_parse_entries(id, table_size, entry_id, handler,
|
|
|
|
NULL, NULL, max_entries);
|
|
|
|
}
|
|
|
|
|
2019-03-26 02:34:01 +08:00
|
|
|
int __init acpi_table_parse_madt(enum acpi_madt_type id,
|
2013-01-12 23:29:38 +08:00
|
|
|
acpi_tbl_entry_handler handler, unsigned int max_entries)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-02-11 11:17:07 +08:00
|
|
|
return acpi_table_parse_entries(ACPI_SIG_MADT,
|
2005-08-05 12:44:28 +08:00
|
|
|
sizeof(struct acpi_table_madt), id,
|
|
|
|
handler, max_entries);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-02-11 10:28:03 +08:00
|
|
|
/**
|
|
|
|
* acpi_table_parse - find table with @id, run @handler on it
|
|
|
|
* @id: table id to find
|
|
|
|
* @handler: handler to run
|
|
|
|
*
|
|
|
|
* Scan the ACPI System Descriptor Table (STD) for a table matching @id,
|
2014-01-06 16:47:59 +08:00
|
|
|
* run @handler on it.
|
|
|
|
*
|
|
|
|
* Return 0 if table found, -errno if not.
|
2007-02-11 10:28:03 +08:00
|
|
|
*/
|
2013-01-12 23:29:38 +08:00
|
|
|
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-02-03 00:48:22 +08:00
|
|
|
struct acpi_table_header *table = NULL;
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2010-02-19 13:09:22 +08:00
|
|
|
if (acpi_disabled)
|
2009-07-08 11:22:58 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
2014-01-06 16:43:54 +08:00
|
|
|
if (!id || !handler)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2007-03-11 15:26:14 +08:00
|
|
|
if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_get_table(id, acpi_apic_instance, &table);
|
2007-03-11 15:26:14 +08:00
|
|
|
else
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_get_table(id, 0, &table);
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2007-02-03 00:48:22 +08:00
|
|
|
if (table) {
|
|
|
|
handler(table);
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_put_table(table);
|
2007-02-03 00:48:22 +08:00
|
|
|
return 0;
|
2007-02-11 10:28:03 +08:00
|
|
|
} else
|
2013-12-05 23:42:38 +08:00
|
|
|
return -ENODEV;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2018-05-01 08:39:05 +08:00
|
|
|
/*
|
2007-03-11 15:26:14 +08:00
|
|
|
* The BIOS is supposed to supply a single APIC/MADT,
|
|
|
|
* but some report two. Provide a knob to use either.
|
|
|
|
* (don't you wish instance 0 and 1 were not the same?)
|
|
|
|
*/
|
|
|
|
static void __init check_multiple_madt(void)
|
|
|
|
{
|
|
|
|
struct acpi_table_header *table = NULL;
|
|
|
|
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_get_table(ACPI_SIG_MADT, 2, &table);
|
2007-03-11 15:26:14 +08:00
|
|
|
if (table) {
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
|
|
|
|
acpi_apic_instance);
|
|
|
|
pr_warn("If \"acpi_apic_instance=%d\" works better, "
|
|
|
|
"notify linux-acpi@vger.kernel.org\n",
|
|
|
|
acpi_apic_instance ? 0 : 2);
|
2016-12-14 15:04:39 +08:00
|
|
|
acpi_put_table(table);
|
2007-03-11 15:26:14 +08:00
|
|
|
|
|
|
|
} else
|
|
|
|
acpi_apic_instance = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-11 10:13:18 +08:00
|
|
|
static void acpi_table_taint(struct acpi_table_header *table)
|
|
|
|
{
|
|
|
|
pr_warn("Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
|
|
|
|
table->signature, table->oem_table_id);
|
|
|
|
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
|
|
|
|
}
|
|
|
|
|
2016-04-11 10:13:33 +08:00
|
|
|
#ifdef CONFIG_ACPI_TABLE_UPGRADE
|
2016-04-11 10:13:18 +08:00
|
|
|
static u64 acpi_tables_addr;
|
|
|
|
static int all_tables_size;
|
|
|
|
|
|
|
|
/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
|
|
|
|
static u8 __init acpi_table_checksum(u8 *buffer, u32 length)
|
|
|
|
{
|
|
|
|
u8 sum = 0;
|
|
|
|
u8 *end = buffer + length;
|
|
|
|
|
|
|
|
while (buffer < end)
|
|
|
|
sum = (u8) (sum + *(buffer++));
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
|
2020-06-17 16:25:05 +08:00
|
|
|
static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = {
|
2019-06-10 20:45:41 +08:00
|
|
|
ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT,
|
|
|
|
ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT,
|
|
|
|
ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT,
|
|
|
|
ACPI_SIG_ASF, ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR,
|
|
|
|
ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG,
|
|
|
|
ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI,
|
|
|
|
ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT,
|
|
|
|
ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT,
|
|
|
|
ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT,
|
|
|
|
ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT,
|
2022-12-09 07:25:36 +08:00
|
|
|
ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI,
|
|
|
|
ACPI_SIG_NBFT };
|
2016-04-11 10:13:18 +08:00
|
|
|
|
|
|
|
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
|
|
|
|
|
2016-04-11 10:13:33 +08:00
|
|
|
#define NR_ACPI_INITRD_TABLES 64
|
|
|
|
static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES];
|
|
|
|
static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
|
2016-04-11 10:13:18 +08:00
|
|
|
|
|
|
|
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
|
|
|
|
|
2016-06-20 18:56:10 +08:00
|
|
|
void __init acpi_table_upgrade(void)
|
2016-04-11 10:13:18 +08:00
|
|
|
{
|
2018-12-18 14:02:45 +08:00
|
|
|
void *data;
|
|
|
|
size_t size;
|
2016-04-11 10:13:18 +08:00
|
|
|
int sig, no, table_nr = 0, total_offset = 0;
|
|
|
|
long offset = 0;
|
|
|
|
struct acpi_table_header *table;
|
|
|
|
char cpio_path[32] = "kernel/firmware/acpi/";
|
|
|
|
struct cpio_data file;
|
|
|
|
|
2018-12-18 14:02:45 +08:00
|
|
|
if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) {
|
|
|
|
data = __initramfs_start;
|
|
|
|
size = __initramfs_size;
|
|
|
|
} else {
|
|
|
|
data = (void *)initrd_start;
|
|
|
|
size = initrd_end - initrd_start;
|
|
|
|
}
|
|
|
|
|
2016-04-11 10:13:18 +08:00
|
|
|
if (data == NULL || size == 0)
|
|
|
|
return;
|
|
|
|
|
2016-04-11 10:13:33 +08:00
|
|
|
for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
|
2016-04-11 10:13:18 +08:00
|
|
|
file = find_cpio_data(cpio_path, data, size, &offset);
|
|
|
|
if (!file.data)
|
|
|
|
break;
|
|
|
|
|
|
|
|
data += offset;
|
|
|
|
size -= offset;
|
|
|
|
|
|
|
|
if (file.size < sizeof(struct acpi_table_header)) {
|
|
|
|
pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n",
|
|
|
|
cpio_path, file.name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
table = file.data;
|
|
|
|
|
2020-06-17 16:25:05 +08:00
|
|
|
for (sig = 0; sig < ARRAY_SIZE(table_sigs); sig++)
|
2016-04-11 10:13:18 +08:00
|
|
|
if (!memcmp(table->signature, table_sigs[sig], 4))
|
|
|
|
break;
|
|
|
|
|
2020-06-17 16:25:05 +08:00
|
|
|
if (sig >= ARRAY_SIZE(table_sigs)) {
|
2016-04-11 10:13:18 +08:00
|
|
|
pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
|
|
|
|
cpio_path, file.name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (file.size != table->length) {
|
|
|
|
pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n",
|
|
|
|
cpio_path, file.name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (acpi_table_checksum(file.data, table->length)) {
|
|
|
|
pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n",
|
|
|
|
cpio_path, file.name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
|
|
|
|
table->signature, cpio_path, file.name, table->length);
|
|
|
|
|
|
|
|
all_tables_size += table->length;
|
|
|
|
acpi_initrd_files[table_nr].data = file.data;
|
|
|
|
acpi_initrd_files[table_nr].size = file.size;
|
|
|
|
table_nr++;
|
|
|
|
}
|
|
|
|
if (table_nr == 0)
|
|
|
|
return;
|
|
|
|
|
2019-08-20 08:17:52 +08:00
|
|
|
if (security_locked_down(LOCKDOWN_ACPI_TABLES)) {
|
|
|
|
pr_notice("kernel is locked down, ignoring table override\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-11 10:13:18 +08:00
|
|
|
acpi_tables_addr =
|
2021-09-03 06:00:26 +08:00
|
|
|
memblock_phys_alloc_range(all_tables_size, PAGE_SIZE,
|
|
|
|
0, ACPI_TABLE_UPGRADE_MAX_PHYS);
|
2016-04-11 10:13:18 +08:00
|
|
|
if (!acpi_tables_addr) {
|
|
|
|
WARN_ON(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Only calling e820_add_reserve does not work and the
|
|
|
|
* tables are invalid (memory got used) later.
|
|
|
|
* memblock_reserve works as expected and the tables won't get modified.
|
|
|
|
* But it's not enough on X86 because ioremap will
|
|
|
|
* complain later (used by acpi_os_map_memory) that the pages
|
|
|
|
* that should get mapped are not marked "reserved".
|
x86/boot/e820: Create coherent API function names for E820 range operations
We have these three related functions:
extern void e820_add_region(u64 start, u64 size, int type);
extern u64 e820_update_range(u64 start, u64 size, unsigned old_type, unsigned new_type);
extern u64 e820_remove_range(u64 start, u64 size, unsigned old_type, int checktype);
But it's not clear from the naming that they are 3 operations based around the
same 'memory range' concept. Rename them to better signal this, and move
the prototypes next to each other:
extern void e820__range_add (u64 start, u64 size, int type);
extern u64 e820__range_update(u64 start, u64 size, unsigned old_type, unsigned new_type);
extern u64 e820__range_remove(u64 start, u64 size, unsigned old_type, int checktype);
Note that this improved organization of the functions shows another problem that was easy
to miss before: sometimes the E820 entry type is 'int', sometimes 'unsigned int' - but this
will be fixed in a separate patch.
No change in functionality.
Cc: Alex Thorlton <athorlton@sgi.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Huang, Ying <ying.huang@intel.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Jackson <pj@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wei Yang <richard.weiyang@gmail.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-01-28 21:19:36 +08:00
|
|
|
* Both memblock_reserve and e820__range_add (via arch_reserve_mem_area)
|
2016-04-11 10:13:18 +08:00
|
|
|
* works fine.
|
|
|
|
*/
|
|
|
|
arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
|
|
|
|
|
2021-10-21 15:09:29 +08:00
|
|
|
kmemleak_ignore_phys(acpi_tables_addr);
|
|
|
|
|
2016-04-11 10:13:18 +08:00
|
|
|
/*
|
|
|
|
* early_ioremap only can remap 256k one time. If we map all
|
|
|
|
* tables one time, we will hit the limit. Need to map chunks
|
|
|
|
* one by one during copying the same as that in relocate_initrd().
|
|
|
|
*/
|
|
|
|
for (no = 0; no < table_nr; no++) {
|
|
|
|
unsigned char *src_p = acpi_initrd_files[no].data;
|
|
|
|
phys_addr_t size = acpi_initrd_files[no].size;
|
|
|
|
phys_addr_t dest_addr = acpi_tables_addr + total_offset;
|
|
|
|
phys_addr_t slop, clen;
|
|
|
|
char *dest_p;
|
|
|
|
|
|
|
|
total_offset += size;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
slop = dest_addr & ~PAGE_MASK;
|
|
|
|
clen = size;
|
|
|
|
if (clen > MAP_CHUNK_SIZE - slop)
|
|
|
|
clen = MAP_CHUNK_SIZE - slop;
|
2016-06-20 18:56:09 +08:00
|
|
|
dest_p = early_memremap(dest_addr & PAGE_MASK,
|
|
|
|
clen + slop);
|
2016-04-11 10:13:18 +08:00
|
|
|
memcpy(dest_p + slop, src_p, clen);
|
2016-06-20 18:56:09 +08:00
|
|
|
early_memunmap(dest_p, clen + slop);
|
2016-04-11 10:13:18 +08:00
|
|
|
src_p += clen;
|
|
|
|
dest_addr += clen;
|
|
|
|
size -= clen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static acpi_status
|
|
|
|
acpi_table_initrd_override(struct acpi_table_header *existing_table,
|
|
|
|
acpi_physical_address *address, u32 *length)
|
|
|
|
{
|
|
|
|
int table_offset = 0;
|
|
|
|
int table_index = 0;
|
|
|
|
struct acpi_table_header *table;
|
|
|
|
u32 table_length;
|
|
|
|
|
|
|
|
*length = 0;
|
|
|
|
*address = 0;
|
|
|
|
if (!acpi_tables_addr)
|
|
|
|
return AE_OK;
|
|
|
|
|
|
|
|
while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
|
|
|
|
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
|
|
|
|
ACPI_HEADER_SIZE);
|
|
|
|
if (table_offset + table->length > all_tables_size) {
|
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
WARN_ON(1);
|
|
|
|
return AE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
table_length = table->length;
|
|
|
|
|
|
|
|
/* Only override tables matched */
|
2016-04-11 10:13:33 +08:00
|
|
|
if (memcmp(existing_table->signature, table->signature, 4) ||
|
|
|
|
memcmp(table->oem_id, existing_table->oem_id,
|
|
|
|
ACPI_OEM_ID_SIZE) ||
|
2016-04-11 10:13:18 +08:00
|
|
|
memcmp(table->oem_table_id, existing_table->oem_table_id,
|
|
|
|
ACPI_OEM_TABLE_ID_SIZE)) {
|
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
goto next_table;
|
|
|
|
}
|
2016-04-11 10:13:33 +08:00
|
|
|
/*
|
|
|
|
* Mark the table to avoid being used in
|
|
|
|
* acpi_table_initrd_scan() and check the revision.
|
|
|
|
*/
|
|
|
|
if (test_and_set_bit(table_index, acpi_initrd_installed) ||
|
|
|
|
existing_table->oem_revision >= table->oem_revision) {
|
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
goto next_table;
|
|
|
|
}
|
2016-04-11 10:13:18 +08:00
|
|
|
|
|
|
|
*length = table_length;
|
|
|
|
*address = acpi_tables_addr + table_offset;
|
2016-04-11 10:13:33 +08:00
|
|
|
pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n",
|
|
|
|
table->signature, table->oem_id,
|
|
|
|
table->oem_table_id);
|
2016-04-11 10:13:18 +08:00
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
next_table:
|
|
|
|
table_offset += table_length;
|
|
|
|
table_index++;
|
|
|
|
}
|
|
|
|
return AE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init acpi_table_initrd_scan(void)
|
|
|
|
{
|
|
|
|
int table_offset = 0;
|
|
|
|
int table_index = 0;
|
|
|
|
u32 table_length;
|
|
|
|
struct acpi_table_header *table;
|
|
|
|
|
|
|
|
if (!acpi_tables_addr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) {
|
|
|
|
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
|
|
|
|
ACPI_HEADER_SIZE);
|
|
|
|
if (table_offset + table->length > all_tables_size) {
|
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
WARN_ON(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
table_length = table->length;
|
|
|
|
|
|
|
|
/* Skip RSDT/XSDT which should only be used for override */
|
2019-04-09 04:42:24 +08:00
|
|
|
if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_RSDT) ||
|
|
|
|
ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_XSDT)) {
|
2016-04-11 10:13:18 +08:00
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
goto next_table;
|
|
|
|
}
|
2016-04-11 10:13:33 +08:00
|
|
|
/*
|
|
|
|
* Mark the table to avoid being used in
|
|
|
|
* acpi_table_initrd_override(). Though this is not possible
|
ACPICA: Use original pointer for virtual origin tables
ACPICA commit dfa3feffa8f760b686207d09dc880cd2f26c72af
Currently the pointer to the table is cast to acpi_physical_address and
later cast back to a pointer to be dereferenced. Whether or not this is
supported is implementation-defined.
On CHERI, and thus Arm's experimental Morello prototype architecture,
pointers are represented as capabilities, which are unforgeable bounded
pointers, providing always-on fine-grained spatial memory safety. This
means that any pointer cast to a plain integer will lose all its
associated metadata, and when cast back to a pointer it will give a
null-derived pointer (one that has the same metadata as null but an
address equal to the integer) that will trap on any dereference. As a
result, this is an implementation where acpi_physical_address cannot be
used as a hack to store real pointers.
Thus, alter the lifecycle of table descriptors. Internal physical tables
keep the current behaviour where only the address is set on install, and
the pointer is set on acquire. Virtual tables (internal and external)
now store the pointer on initialisation and use that on acquire (which
will redundantly set *table_ptr to itself, but changing that is both
unnecessary and overly complicated as acpi_tb_acquire_table is called with
both a pointer to a variable and a pointer to Table->Pointer itself).
This requires propagating the (possible) table pointer everywhere in
order to make sure pointers make it through to acpi_tb_acquire_temp_table,
which requires a change to the acpi_install_table interface. Instead of
taking an ACPI_PHYSADDR_TYPE and a boolean indicating whether it's
physical or virtual, it is now split into acpi_install_table (that takes
an external virtual table pointer) and acpi_install_physical_table (that
takes an ACPI_PHYSADDR_TYPE for an internal physical table address).
This also has the benefit of providing a cleaner API.
Link: https://github.com/acpica/acpica/commit/dfa3feff
Signed-off-by: Bob Moore <robert.moore@intel.com>
[ rjw: Adjust the code in tables.c to match interface changes ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-12-23 00:22:28 +08:00
|
|
|
* because override is disabled in acpi_install_physical_table().
|
2016-04-11 10:13:33 +08:00
|
|
|
*/
|
|
|
|
if (test_and_set_bit(table_index, acpi_initrd_installed)) {
|
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
|
|
goto next_table;
|
|
|
|
}
|
2016-04-11 10:13:18 +08:00
|
|
|
|
2016-04-11 10:13:33 +08:00
|
|
|
pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n",
|
|
|
|
table->signature, table->oem_id,
|
|
|
|
table->oem_table_id);
|
2016-04-11 10:13:18 +08:00
|
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
ACPICA: Use original pointer for virtual origin tables
ACPICA commit dfa3feffa8f760b686207d09dc880cd2f26c72af
Currently the pointer to the table is cast to acpi_physical_address and
later cast back to a pointer to be dereferenced. Whether or not this is
supported is implementation-defined.
On CHERI, and thus Arm's experimental Morello prototype architecture,
pointers are represented as capabilities, which are unforgeable bounded
pointers, providing always-on fine-grained spatial memory safety. This
means that any pointer cast to a plain integer will lose all its
associated metadata, and when cast back to a pointer it will give a
null-derived pointer (one that has the same metadata as null but an
address equal to the integer) that will trap on any dereference. As a
result, this is an implementation where acpi_physical_address cannot be
used as a hack to store real pointers.
Thus, alter the lifecycle of table descriptors. Internal physical tables
keep the current behaviour where only the address is set on install, and
the pointer is set on acquire. Virtual tables (internal and external)
now store the pointer on initialisation and use that on acquire (which
will redundantly set *table_ptr to itself, but changing that is both
unnecessary and overly complicated as acpi_tb_acquire_table is called with
both a pointer to a variable and a pointer to Table->Pointer itself).
This requires propagating the (possible) table pointer everywhere in
order to make sure pointers make it through to acpi_tb_acquire_temp_table,
which requires a change to the acpi_install_table interface. Instead of
taking an ACPI_PHYSADDR_TYPE and a boolean indicating whether it's
physical or virtual, it is now split into acpi_install_table (that takes
an external virtual table pointer) and acpi_install_physical_table (that
takes an ACPI_PHYSADDR_TYPE for an internal physical table address).
This also has the benefit of providing a cleaner API.
Link: https://github.com/acpica/acpica/commit/dfa3feff
Signed-off-by: Bob Moore <robert.moore@intel.com>
[ rjw: Adjust the code in tables.c to match interface changes ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-12-23 00:22:28 +08:00
|
|
|
acpi_install_physical_table(acpi_tables_addr + table_offset);
|
2016-04-11 10:13:18 +08:00
|
|
|
next_table:
|
|
|
|
table_offset += table_length;
|
|
|
|
table_index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static acpi_status
|
|
|
|
acpi_table_initrd_override(struct acpi_table_header *existing_table,
|
|
|
|
acpi_physical_address *address,
|
|
|
|
u32 *table_length)
|
|
|
|
{
|
|
|
|
*table_length = 0;
|
|
|
|
*address = 0;
|
|
|
|
return AE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init acpi_table_initrd_scan(void)
|
|
|
|
{
|
|
|
|
}
|
2016-04-11 10:13:33 +08:00
|
|
|
#endif /* CONFIG_ACPI_TABLE_UPGRADE */
|
2016-04-11 10:13:18 +08:00
|
|
|
|
|
|
|
acpi_status
|
|
|
|
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
|
|
|
|
acpi_physical_address *address,
|
|
|
|
u32 *table_length)
|
|
|
|
{
|
|
|
|
return acpi_table_initrd_override(existing_table, address,
|
|
|
|
table_length);
|
|
|
|
}
|
|
|
|
|
2018-12-21 03:38:56 +08:00
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
2018-11-13 18:46:23 +08:00
|
|
|
static void *amlcode __attribute__ ((weakref("AmlCode")));
|
|
|
|
static void *dsdt_amlcode __attribute__ ((weakref("dsdt_aml_code")));
|
2018-12-21 03:38:56 +08:00
|
|
|
#endif
|
2018-11-13 18:46:23 +08:00
|
|
|
|
2019-03-26 02:34:01 +08:00
|
|
|
acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
|
2016-04-11 10:13:18 +08:00
|
|
|
struct acpi_table_header **new_table)
|
|
|
|
{
|
|
|
|
if (!existing_table || !new_table)
|
|
|
|
return AE_BAD_PARAMETER;
|
|
|
|
|
|
|
|
*new_table = NULL;
|
|
|
|
|
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
2018-11-13 18:46:23 +08:00
|
|
|
if (!strncmp(existing_table->signature, "DSDT", 4)) {
|
|
|
|
*new_table = (struct acpi_table_header *)&amlcode;
|
|
|
|
if (!(*new_table))
|
|
|
|
*new_table = (struct acpi_table_header *)&dsdt_amlcode;
|
|
|
|
}
|
2016-04-11 10:13:18 +08:00
|
|
|
#endif
|
|
|
|
if (*new_table != NULL)
|
|
|
|
acpi_table_taint(existing_table);
|
|
|
|
return AE_OK;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2021-03-24 03:26:52 +08:00
|
|
|
* acpi_locate_initial_tables()
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2022-11-04 16:54:38 +08:00
|
|
|
* Get the RSDP, then find and checksum all the ACPI tables.
|
2007-02-03 00:48:22 +08:00
|
|
|
*
|
2022-11-04 16:54:38 +08:00
|
|
|
* result: initial_tables[] is initialized, and points to
|
|
|
|
* a list of ACPI tables.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2021-03-24 03:26:52 +08:00
|
|
|
int __init acpi_locate_initial_tables(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-02-07 03:00:56 +08:00
|
|
|
acpi_status status;
|
|
|
|
|
2014-05-31 08:15:02 +08:00
|
|
|
if (acpi_verify_table_checksum) {
|
|
|
|
pr_info("Early table checksum verification enabled\n");
|
2017-07-10 15:23:45 +08:00
|
|
|
acpi_gbl_enable_table_validation = TRUE;
|
2014-05-31 08:15:02 +08:00
|
|
|
} else {
|
|
|
|
pr_info("Early table checksum verification disabled\n");
|
2017-07-10 15:23:45 +08:00
|
|
|
acpi_gbl_enable_table_validation = FALSE;
|
2014-05-31 08:15:02 +08:00
|
|
|
}
|
|
|
|
|
2009-02-07 03:00:56 +08:00
|
|
|
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
|
|
|
|
if (ACPI_FAILURE(status))
|
2013-12-05 23:42:38 +08:00
|
|
|
return -EINVAL;
|
2009-02-07 03:00:56 +08:00
|
|
|
|
2021-03-24 03:26:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init acpi_reserve_initial_tables(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ACPI_MAX_TABLES; i++) {
|
|
|
|
struct acpi_table_desc *table_desc = &initial_tables[i];
|
|
|
|
u64 start = table_desc->address;
|
|
|
|
u64 size = table_desc->length;
|
|
|
|
|
|
|
|
if (!start || !size)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pr_info("Reserving %4s table memory at [mem 0x%llx-0x%llx]\n",
|
|
|
|
table_desc->signature.ascii, start, start + size - 1);
|
|
|
|
|
|
|
|
memblock_reserve(start, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init acpi_table_init_complete(void)
|
|
|
|
{
|
|
|
|
acpi_table_initrd_scan();
|
2007-03-11 15:26:14 +08:00
|
|
|
check_multiple_madt();
|
2021-03-24 03:26:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int __init acpi_table_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = acpi_locate_initial_tables();
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
acpi_table_init_complete();
|
|
|
|
|
2007-03-11 15:26:14 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init acpi_parse_apic_instance(char *str)
|
|
|
|
{
|
2008-08-21 07:41:45 +08:00
|
|
|
if (!str)
|
|
|
|
return -EINVAL;
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2014-06-14 03:49:58 +08:00
|
|
|
if (kstrtoint(str, 0, &acpi_apic_instance))
|
|
|
|
return -EINVAL;
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2014-02-20 15:45:33 +08:00
|
|
|
pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
|
2007-03-11 15:26:14 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-03-11 15:26:14 +08:00
|
|
|
early_param("acpi_apic_instance", acpi_parse_apic_instance);
|
2014-05-31 08:15:02 +08:00
|
|
|
|
|
|
|
static int __init acpi_force_table_verification_setup(char *s)
|
|
|
|
{
|
|
|
|
acpi_verify_table_checksum = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
|
2016-01-22 01:05:47 +08:00
|
|
|
|
|
|
|
static int __init acpi_force_32bit_fadt_addr(char *s)
|
|
|
|
{
|
|
|
|
pr_info("Forcing 32 Bit FADT addresses\n");
|
|
|
|
acpi_gbl_use32_bit_fadt_addresses = TRUE;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
early_param("acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr);
|