WSL2-Linux-Kernel/drivers/acpi/tables.c

887 строки
23 KiB
C
Исходник Обычный вид История

treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 157 Based on 3 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* acpi_tables.c - ACPI Boot-Time Table Parsing
*
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*/
/* Uncomment next line to get verbose printout */
/* #define DEBUG */
#define pr_fmt(fmt) "ACPI: " fmt
#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>
#include <linux/memblock.h>
mm: remove include/linux/bootmem.h Move remaining definitions and declarations from include/linux/bootmem.h into include/linux/memblock.h and remove the redundant header. The includes were replaced with the semantic patch below and then semi-automated removal of duplicated '#include <linux/memblock.h> @@ @@ - #include <linux/bootmem.h> + #include <linux/memblock.h> [sfr@canb.auug.org.au: dma-direct: fix up for the removal of linux/bootmem.h] Link: http://lkml.kernel.org/r/20181002185342.133d1680@canb.auug.org.au [sfr@canb.auug.org.au: powerpc: fix up for removal of linux/bootmem.h] Link: http://lkml.kernel.org/r/20181005161406.73ef8727@canb.auug.org.au [sfr@canb.auug.org.au: x86/kaslr, ACPI/NUMA: fix for linux/bootmem.h removal] Link: http://lkml.kernel.org/r/20181008190341.5e396491@canb.auug.org.au Link: http://lkml.kernel.org/r/1536927045-23536-30-git-send-email-rppt@linux.vnet.ibm.com Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Ingo Molnar <mingo@redhat.com> Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> Cc: Jonas Bonn <jonas@southpole.se> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Ley Foon Tan <lftan@altera.com> Cc: Mark Salter <msalter@redhat.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Matt Turner <mattst88@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Simek <monstr@monstr.eu> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: Paul Burton <paul.burton@mips.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Serge Semin <fancer.lancer@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-31 01:09:49 +03:00
#include <linux/earlycpio.h>
#include <linux/initrd.h>
#include <linux/security.h>
#include "internal.h"
#ifdef CONFIG_ACPI_CUSTOM_DSDT
#include CONFIG_ACPI_CUSTOM_DSDT_FILE
#endif
#define ACPI_MAX_TABLES 128
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
static int acpi_apic_instance __initdata;
enum acpi_subtable_type {
ACPI_SUBTABLE_COMMON,
ACPI_SUBTABLE_HMAT,
ACPI: PRM: implement OperationRegion handler for the PlatformRtMechanism subtype Platform Runtime Mechanism (PRM) is a firmware interface that exposes a set of binary executables that can either be called from the AML interpreter or device drivers by bypassing the AML interpreter. This change implements the AML interpreter path. According to the specification [1], PRM services are listed in an ACPI table called the PRMT. This patch parses module and handler information listed in the PRMT and registers the PlatformRtMechanism OpRegion handler before ACPI tables are loaded. Each service is defined by a 16-byte GUID and called from writing a 26-byte ASL buffer containing the identifier to a FieldUnit object defined inside a PlatformRtMechanism OperationRegion. OperationRegion (PRMR, PlatformRtMechanism, 0, 26) Field (PRMR, BufferAcc, NoLock, Preserve) { PRMF, 208 // Write to this field to invoke the OperationRegion Handler } The 26-byte ASL buffer is defined as the following: Byte Offset Byte Length Description ============================================================= 0 1 PRM OperationRegion handler status 1 8 PRM service status 9 1 PRM command 10 16 PRM handler GUID The ASL caller fills out a 26-byte buffer containing the PRM command and the PRM handler GUID like so: /* Local0 is the PRM data buffer */ Local0 = buffer (26){} /* Create byte fields over the buffer */ CreateByteField (Local0, 0x9, CMD) CreateField (Local0, 0x50, 0x80, GUID) /* Fill in the command and data fields of the data buffer */ CMD = 0 // run command GUID = ToUUID("xxxx-xx-xxx-xxxx") /* * Invoke PRM service with an ID that matches GUID and save the * result. */ Local0 = (\_SB.PRMT.PRMF = Local0) Byte offset 0 - 8 are written by the handler as a status passed back to AML and used by ASL like so: /* Create byte fields over the buffer */ CreateByteField (Local0, 0x0, PSTA) CreateQWordField (Local0, 0x1, USTA) In this ASL code, PSTA contains a status from the OperationRegion and USTA contains a status from the PRM service. The 26-byte buffer is recieved by acpi_platformrt_space_handler. This handler will look at the command value and the handler guid and take the approperiate actions. Command value Action ===================================================================== 0 Run the PRM service indicated by the PRM handler GUID (bytes 10-26) 1 Prevent PRM runtime updates from happening to the service's parent module 2 Allow PRM updates from happening to the service's parent module This patch enables command value 0. Link: https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf # [1] Signed-off-by: Erik Kaneda <erik.kaneda@intel.com> [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-06-10 06:41:52 +03:00
ACPI_SUBTABLE_PRMT,
};
struct acpi_subtable_entry {
union acpi_subtable_headers *hdr;
enum acpi_subtable_type type;
};
ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [<ffffffff817c627b>] dump_stack+0x45/0x56 [<ffffffff81067b5d>] warn_slowpath_common+0x7d/0xa0 [<ffffffff81067c3a>] warn_slowpath_null+0x1a/0x20 [<ffffffff81d4b9d5>] __early_ioremap+0x11f/0x1f2 [<ffffffff81d4bc5b>] early_ioremap+0x13/0x15 [<ffffffff81d2b8f3>] __acpi_map_table+0x13/0x18 [<ffffffff817b8d1a>] acpi_os_map_memory+0x26/0x14e [<ffffffff813ff018>] acpi_tb_acquire_table+0x42/0x70 [<ffffffff813ff086>] acpi_tb_validate_table+0x27/0x37 [<ffffffff813ff0e5>] acpi_tb_verify_table+0x22/0xd8 [<ffffffff813ff6a8>] acpi_tb_install_non_fixed_table+0x60/0x1c9 [<ffffffff81d61024>] acpi_tb_parse_root_table+0x218/0x26a [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d610cd>] acpi_initialize_tables+0x57/0x59 [<ffffffff81d5f25d>] acpi_table_init+0x1b/0x99 [<ffffffff81d2bca0>] acpi_boot_table_init+0x1e/0x85 [<ffffffff81d23043>] setup_arch+0x99d/0xcc6 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1bbbe>] start_kernel+0x8b/0x415 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1b5ee>] x86_64_start_reservations+0x2a/0x2c [<ffffffff81d1b72e>] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-tested-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-31 04:15:02 +04:00
/*
* Disable table checksum verification for the early stage due to the size
* limitation of the current x86 early mapping implementation.
*/
static bool acpi_verify_table_checksum __initdata = false;
void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
if (!header)
return;
switch (header->type) {
case ACPI_MADT_TYPE_LOCAL_APIC:
{
struct acpi_madt_local_apic *p =
(struct acpi_madt_local_apic *)header;
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");
}
break;
case ACPI_MADT_TYPE_LOCAL_X2APIC:
{
struct acpi_madt_local_x2apic *p =
(struct acpi_madt_local_x2apic *)header;
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");
}
break;
case ACPI_MADT_TYPE_IO_APIC:
{
struct acpi_madt_io_apic *p =
(struct acpi_madt_io_apic *)header;
pr_debug("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
p->id, p->address, p->global_irq_base);
}
break;
case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
{
struct acpi_madt_interrupt_override *p =
(struct acpi_madt_interrupt_override *)header;
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]);
if (p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
}
break;
case ACPI_MADT_TYPE_NMI_SOURCE:
{
struct acpi_madt_nmi_source *p =
(struct acpi_madt_nmi_source *)header;
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);
}
break;
case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
{
struct acpi_madt_local_apic_nmi *p =
(struct acpi_madt_local_apic_nmi *)header;
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);
}
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;
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);
}
break;
case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
{
struct acpi_madt_local_apic_override *p =
(struct acpi_madt_local_apic_override *)header;
pr_info("LAPIC_ADDR_OVR (address[%p])\n",
(void *)(unsigned long)p->address);
}
break;
case ACPI_MADT_TYPE_IO_SAPIC:
{
struct acpi_madt_io_sapic *p =
(struct acpi_madt_io_sapic *)header;
pr_debug("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
p->id, (void *)(unsigned long)p->address,
p->global_irq_base);
}
break;
case ACPI_MADT_TYPE_LOCAL_SAPIC:
{
struct acpi_madt_local_sapic *p =
(struct acpi_madt_local_sapic *)header;
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");
}
break;
case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
{
struct acpi_madt_interrupt_source *p =
(struct acpi_madt_interrupt_source *)header;
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);
}
break;
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;
default:
pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
header->type);
break;
}
}
static unsigned long __init
acpi_get_entry_type(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
case ACPI_SUBTABLE_COMMON:
return entry->hdr->common.type;
case ACPI_SUBTABLE_HMAT:
return entry->hdr->hmat.type;
ACPI: PRM: implement OperationRegion handler for the PlatformRtMechanism subtype Platform Runtime Mechanism (PRM) is a firmware interface that exposes a set of binary executables that can either be called from the AML interpreter or device drivers by bypassing the AML interpreter. This change implements the AML interpreter path. According to the specification [1], PRM services are listed in an ACPI table called the PRMT. This patch parses module and handler information listed in the PRMT and registers the PlatformRtMechanism OpRegion handler before ACPI tables are loaded. Each service is defined by a 16-byte GUID and called from writing a 26-byte ASL buffer containing the identifier to a FieldUnit object defined inside a PlatformRtMechanism OperationRegion. OperationRegion (PRMR, PlatformRtMechanism, 0, 26) Field (PRMR, BufferAcc, NoLock, Preserve) { PRMF, 208 // Write to this field to invoke the OperationRegion Handler } The 26-byte ASL buffer is defined as the following: Byte Offset Byte Length Description ============================================================= 0 1 PRM OperationRegion handler status 1 8 PRM service status 9 1 PRM command 10 16 PRM handler GUID The ASL caller fills out a 26-byte buffer containing the PRM command and the PRM handler GUID like so: /* Local0 is the PRM data buffer */ Local0 = buffer (26){} /* Create byte fields over the buffer */ CreateByteField (Local0, 0x9, CMD) CreateField (Local0, 0x50, 0x80, GUID) /* Fill in the command and data fields of the data buffer */ CMD = 0 // run command GUID = ToUUID("xxxx-xx-xxx-xxxx") /* * Invoke PRM service with an ID that matches GUID and save the * result. */ Local0 = (\_SB.PRMT.PRMF = Local0) Byte offset 0 - 8 are written by the handler as a status passed back to AML and used by ASL like so: /* Create byte fields over the buffer */ CreateByteField (Local0, 0x0, PSTA) CreateQWordField (Local0, 0x1, USTA) In this ASL code, PSTA contains a status from the OperationRegion and USTA contains a status from the PRM service. The 26-byte buffer is recieved by acpi_platformrt_space_handler. This handler will look at the command value and the handler guid and take the approperiate actions. Command value Action ===================================================================== 0 Run the PRM service indicated by the PRM handler GUID (bytes 10-26) 1 Prevent PRM runtime updates from happening to the service's parent module 2 Allow PRM updates from happening to the service's parent module This patch enables command value 0. Link: https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf # [1] Signed-off-by: Erik Kaneda <erik.kaneda@intel.com> [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-06-10 06:41:52 +03:00
case ACPI_SUBTABLE_PRMT:
return 0;
}
return 0;
}
static unsigned long __init
acpi_get_entry_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
case ACPI_SUBTABLE_COMMON:
return entry->hdr->common.length;
case ACPI_SUBTABLE_HMAT:
return entry->hdr->hmat.length;
ACPI: PRM: implement OperationRegion handler for the PlatformRtMechanism subtype Platform Runtime Mechanism (PRM) is a firmware interface that exposes a set of binary executables that can either be called from the AML interpreter or device drivers by bypassing the AML interpreter. This change implements the AML interpreter path. According to the specification [1], PRM services are listed in an ACPI table called the PRMT. This patch parses module and handler information listed in the PRMT and registers the PlatformRtMechanism OpRegion handler before ACPI tables are loaded. Each service is defined by a 16-byte GUID and called from writing a 26-byte ASL buffer containing the identifier to a FieldUnit object defined inside a PlatformRtMechanism OperationRegion. OperationRegion (PRMR, PlatformRtMechanism, 0, 26) Field (PRMR, BufferAcc, NoLock, Preserve) { PRMF, 208 // Write to this field to invoke the OperationRegion Handler } The 26-byte ASL buffer is defined as the following: Byte Offset Byte Length Description ============================================================= 0 1 PRM OperationRegion handler status 1 8 PRM service status 9 1 PRM command 10 16 PRM handler GUID The ASL caller fills out a 26-byte buffer containing the PRM command and the PRM handler GUID like so: /* Local0 is the PRM data buffer */ Local0 = buffer (26){} /* Create byte fields over the buffer */ CreateByteField (Local0, 0x9, CMD) CreateField (Local0, 0x50, 0x80, GUID) /* Fill in the command and data fields of the data buffer */ CMD = 0 // run command GUID = ToUUID("xxxx-xx-xxx-xxxx") /* * Invoke PRM service with an ID that matches GUID and save the * result. */ Local0 = (\_SB.PRMT.PRMF = Local0) Byte offset 0 - 8 are written by the handler as a status passed back to AML and used by ASL like so: /* Create byte fields over the buffer */ CreateByteField (Local0, 0x0, PSTA) CreateQWordField (Local0, 0x1, USTA) In this ASL code, PSTA contains a status from the OperationRegion and USTA contains a status from the PRM service. The 26-byte buffer is recieved by acpi_platformrt_space_handler. This handler will look at the command value and the handler guid and take the approperiate actions. Command value Action ===================================================================== 0 Run the PRM service indicated by the PRM handler GUID (bytes 10-26) 1 Prevent PRM runtime updates from happening to the service's parent module 2 Allow PRM updates from happening to the service's parent module This patch enables command value 0. Link: https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf # [1] Signed-off-by: Erik Kaneda <erik.kaneda@intel.com> [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-06-10 06:41:52 +03:00
case ACPI_SUBTABLE_PRMT:
return entry->hdr->prmt.length;
}
return 0;
}
static unsigned long __init
acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
case ACPI_SUBTABLE_COMMON:
return sizeof(entry->hdr->common);
case ACPI_SUBTABLE_HMAT:
return sizeof(entry->hdr->hmat);
ACPI: PRM: implement OperationRegion handler for the PlatformRtMechanism subtype Platform Runtime Mechanism (PRM) is a firmware interface that exposes a set of binary executables that can either be called from the AML interpreter or device drivers by bypassing the AML interpreter. This change implements the AML interpreter path. According to the specification [1], PRM services are listed in an ACPI table called the PRMT. This patch parses module and handler information listed in the PRMT and registers the PlatformRtMechanism OpRegion handler before ACPI tables are loaded. Each service is defined by a 16-byte GUID and called from writing a 26-byte ASL buffer containing the identifier to a FieldUnit object defined inside a PlatformRtMechanism OperationRegion. OperationRegion (PRMR, PlatformRtMechanism, 0, 26) Field (PRMR, BufferAcc, NoLock, Preserve) { PRMF, 208 // Write to this field to invoke the OperationRegion Handler } The 26-byte ASL buffer is defined as the following: Byte Offset Byte Length Description ============================================================= 0 1 PRM OperationRegion handler status 1 8 PRM service status 9 1 PRM command 10 16 PRM handler GUID The ASL caller fills out a 26-byte buffer containing the PRM command and the PRM handler GUID like so: /* Local0 is the PRM data buffer */ Local0 = buffer (26){} /* Create byte fields over the buffer */ CreateByteField (Local0, 0x9, CMD) CreateField (Local0, 0x50, 0x80, GUID) /* Fill in the command and data fields of the data buffer */ CMD = 0 // run command GUID = ToUUID("xxxx-xx-xxx-xxxx") /* * Invoke PRM service with an ID that matches GUID and save the * result. */ Local0 = (\_SB.PRMT.PRMF = Local0) Byte offset 0 - 8 are written by the handler as a status passed back to AML and used by ASL like so: /* Create byte fields over the buffer */ CreateByteField (Local0, 0x0, PSTA) CreateQWordField (Local0, 0x1, USTA) In this ASL code, PSTA contains a status from the OperationRegion and USTA contains a status from the PRM service. The 26-byte buffer is recieved by acpi_platformrt_space_handler. This handler will look at the command value and the handler guid and take the approperiate actions. Command value Action ===================================================================== 0 Run the PRM service indicated by the PRM handler GUID (bytes 10-26) 1 Prevent PRM runtime updates from happening to the service's parent module 2 Allow PRM updates from happening to the service's parent module This patch enables command value 0. Link: https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf # [1] Signed-off-by: Erik Kaneda <erik.kaneda@intel.com> [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-06-10 06:41:52 +03:00
case ACPI_SUBTABLE_PRMT:
return sizeof(entry->hdr->prmt);
}
return 0;
}
static enum acpi_subtable_type __init
acpi_get_subtable_type(char *id)
{
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
return ACPI_SUBTABLE_HMAT;
ACPI: PRM: implement OperationRegion handler for the PlatformRtMechanism subtype Platform Runtime Mechanism (PRM) is a firmware interface that exposes a set of binary executables that can either be called from the AML interpreter or device drivers by bypassing the AML interpreter. This change implements the AML interpreter path. According to the specification [1], PRM services are listed in an ACPI table called the PRMT. This patch parses module and handler information listed in the PRMT and registers the PlatformRtMechanism OpRegion handler before ACPI tables are loaded. Each service is defined by a 16-byte GUID and called from writing a 26-byte ASL buffer containing the identifier to a FieldUnit object defined inside a PlatformRtMechanism OperationRegion. OperationRegion (PRMR, PlatformRtMechanism, 0, 26) Field (PRMR, BufferAcc, NoLock, Preserve) { PRMF, 208 // Write to this field to invoke the OperationRegion Handler } The 26-byte ASL buffer is defined as the following: Byte Offset Byte Length Description ============================================================= 0 1 PRM OperationRegion handler status 1 8 PRM service status 9 1 PRM command 10 16 PRM handler GUID The ASL caller fills out a 26-byte buffer containing the PRM command and the PRM handler GUID like so: /* Local0 is the PRM data buffer */ Local0 = buffer (26){} /* Create byte fields over the buffer */ CreateByteField (Local0, 0x9, CMD) CreateField (Local0, 0x50, 0x80, GUID) /* Fill in the command and data fields of the data buffer */ CMD = 0 // run command GUID = ToUUID("xxxx-xx-xxx-xxxx") /* * Invoke PRM service with an ID that matches GUID and save the * result. */ Local0 = (\_SB.PRMT.PRMF = Local0) Byte offset 0 - 8 are written by the handler as a status passed back to AML and used by ASL like so: /* Create byte fields over the buffer */ CreateByteField (Local0, 0x0, PSTA) CreateQWordField (Local0, 0x1, USTA) In this ASL code, PSTA contains a status from the OperationRegion and USTA contains a status from the PRM service. The 26-byte buffer is recieved by acpi_platformrt_space_handler. This handler will look at the command value and the handler guid and take the approperiate actions. Command value Action ===================================================================== 0 Run the PRM service indicated by the PRM handler GUID (bytes 10-26) 1 Prevent PRM runtime updates from happening to the service's parent module 2 Allow PRM updates from happening to the service's parent module This patch enables command value 0. Link: https://uefi.org/sites/default/files/resources/Platform%20Runtime%20Mechanism%20-%20with%20legal%20notice.pdf # [1] Signed-off-by: Erik Kaneda <erik.kaneda@intel.com> [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-06-10 06:41:52 +03:00
if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
return ACPI_SUBTABLE_PRMT;
return ACPI_SUBTABLE_COMMON;
}
/**
* acpi_parse_entries_array - for each proc_num find a suitable subtable
*
* @id: table id (for debugging purposes)
* @table_size: size of the root table
* @table_header: where does the table start?
* @proc: array of acpi_subtable_proc struct containing entry id
* and associated handler with it
* @proc_num: how big proc is?
* @max_entries: how many entries can we process?
*
* For each proc_num find a subtable with proc->id and run proc->handler
* on it. Assumption is that there's only single handler for particular
* entry id.
*
* The table_size is not the size of the complete ACPI table (the length
* field in the header struct), but only the size of the root table; i.e.,
* the offset from the very first byte of the complete ACPI table, to the
* first byte of the very first subtable.
*
* On success returns sum of all matching entries for all proc handlers.
* Otherwise, -ENODEV or -EINVAL is returned.
*/
static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
struct acpi_table_header *table_header,
struct acpi_subtable_proc *proc, int proc_num,
unsigned int max_entries)
{
struct acpi_subtable_entry entry;
unsigned long table_end, subtable_len, entry_len;
int count = 0;
ACPI / tables: fix acpi_parse_entries_array() so it traverses all subtables The acpi_parse_entries_array() function currently returns the very first time there is any error found by one of the callback functions, or if one of the callbacks returns a non-zero value. However, the ACPI subtables being traversed could still have valid entries that could be used by one of the callback functions. And, if the comments are correct, that is what should happen -- always traverse all of the subtables, calling as many of the callbacks as possible. This patch makes the function consistent with its description so that it will properly invoke all callbacks for all matching entries, for all subtables, instead of stopping abruptly as it does today. This does change the semantics of using acpi_parse_entries_array(). In examining all users of the function, none of them rely on the current behavior; that is, there appears to be no assumption that either all subtables are traversed and all callbacks invoked, or that the function will return immediately on any error from a callback. Each callback operates independently. Hence, there should be no functional change due to this change in semantics. Future patches being prepared will rely on this new behavior; indeed, they were written assuming the acpi_parse_entries_array() function operated as its comments describe. For example, a callback that counts the number of subtables of a specific type can now be assured that as many subtables as possible have been enumerated. Signed-off-by: Al Stone <ahs3@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-08-20 03:48:12 +03:00
int errs = 0;
int i;
table_end = (unsigned long)table_header + table_header->length;
/* Parse all entries looking for a match. */
entry.type = acpi_get_subtable_type(id);
entry.hdr = (union acpi_subtable_headers *)
((unsigned long)table_header + table_size);
subtable_len = acpi_get_subtable_header_length(&entry);
while (((unsigned long)entry.hdr) + subtable_len < table_end) {
if (max_entries && count >= max_entries)
break;
for (i = 0; i < proc_num; i++) {
if (acpi_get_entry_type(&entry) != proc[i].id)
continue;
if (!proc[i].handler ||
(!errs && proc[i].handler(entry.hdr, table_end))) {
ACPI / tables: fix acpi_parse_entries_array() so it traverses all subtables The acpi_parse_entries_array() function currently returns the very first time there is any error found by one of the callback functions, or if one of the callbacks returns a non-zero value. However, the ACPI subtables being traversed could still have valid entries that could be used by one of the callback functions. And, if the comments are correct, that is what should happen -- always traverse all of the subtables, calling as many of the callbacks as possible. This patch makes the function consistent with its description so that it will properly invoke all callbacks for all matching entries, for all subtables, instead of stopping abruptly as it does today. This does change the semantics of using acpi_parse_entries_array(). In examining all users of the function, none of them rely on the current behavior; that is, there appears to be no assumption that either all subtables are traversed and all callbacks invoked, or that the function will return immediately on any error from a callback. Each callback operates independently. Hence, there should be no functional change due to this change in semantics. Future patches being prepared will rely on this new behavior; indeed, they were written assuming the acpi_parse_entries_array() function operated as its comments describe. For example, a callback that counts the number of subtables of a specific type can now be assured that as many subtables as possible have been enumerated. Signed-off-by: Al Stone <ahs3@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-08-20 03:48:12 +03:00
errs++;
continue;
}
ACPI / tables: fix incorrect counts returned by acpi_parse_entries_array() The static function acpi_parse_entries_array() is provided an array of type struct acpi_subtable_proc that has a callback function and a count. The count should reflect how many times the callback has been called. However, the current code only increments the 0th element of the array, regardless of the number of entries in the array, or which callback has been invoked. The result is that we know the total number of callbacks made but we cannot determine which callbacks were made, nor how often. The fix is to index into the array of structs and increment the proper counts. There is one place in the x86 code for acpi_parse_madt_lapic_entries() where the counts for each callback are used. If no LAPICs *and* no X2APICs are found, an ENODEV is supposed to be returned; as it stands, the count of X2APICs will always be zero, regardless of what is in the MADT. Should there be no LAPICs, ENODEV will be returned in error, if there are X2APICs in the MADT. Otherwise, there are no other functional consequences of the count being done as it currently is; all other uses simply check that the return value from acpi_parse_entries_array() or passed back via its callers is either non-zero, an error, or in one case just ignored. In future patches, I will also need these counts to be correct; I need to count the number of instances of subtables of certain types within the MADT to determine whether or not an ACPI IORT is required or not, and report when it is not present when it should be. Signed-off-by: Al Stone <ahs3@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-08-20 03:48:11 +03:00
proc[i].count++;
break;
}
if (i != proc_num)
count++;
/*
* If entry->length is 0, break from this loop to avoid
* infinite loop.
*/
entry_len = acpi_get_entry_length(&entry);
if (entry_len == 0) {
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
return -EINVAL;
}
entry.hdr = (union acpi_subtable_headers *)
((unsigned long)entry.hdr + entry_len);
}
if (max_entries && count > max_entries) {
pr_warn("[%4.4s:0x%02x] found the maximum %i entries\n",
id, proc->id, count);
}
ACPI / tables: fix acpi_parse_entries_array() so it traverses all subtables The acpi_parse_entries_array() function currently returns the very first time there is any error found by one of the callback functions, or if one of the callbacks returns a non-zero value. However, the ACPI subtables being traversed could still have valid entries that could be used by one of the callback functions. And, if the comments are correct, that is what should happen -- always traverse all of the subtables, calling as many of the callbacks as possible. This patch makes the function consistent with its description so that it will properly invoke all callbacks for all matching entries, for all subtables, instead of stopping abruptly as it does today. This does change the semantics of using acpi_parse_entries_array(). In examining all users of the function, none of them rely on the current behavior; that is, there appears to be no assumption that either all subtables are traversed and all callbacks invoked, or that the function will return immediately on any error from a callback. Each callback operates independently. Hence, there should be no functional change due to this change in semantics. Future patches being prepared will rely on this new behavior; indeed, they were written assuming the acpi_parse_entries_array() function operated as its comments describe. For example, a callback that counts the number of subtables of a specific type can now be assured that as many subtables as possible have been enumerated. Signed-off-by: Al Stone <ahs3@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-08-20 03:48:12 +03:00
return errs ? -EINVAL : count;
}
int __init acpi_table_parse_entries_array(char *id,
unsigned long table_size,
struct acpi_subtable_proc *proc, int proc_num,
unsigned int max_entries)
{
struct acpi_table_header *table_header = NULL;
int count;
u32 instance = 0;
if (acpi_disabled)
return -ENODEV;
if (!id)
return -EINVAL;
if (!table_size)
return -EINVAL;
if (!strncmp(id, ACPI_SIG_MADT, 4))
instance = acpi_apic_instance;
acpi_get_table(id, instance, &table_header);
if (!table_header) {
pr_warn("%4.4s not present\n", id);
return -ENODEV;
}
count = acpi_parse_entries_array(id, table_size, table_header,
proc, proc_num, max_entries);
acpi_put_table(table_header);
return count;
}
int __init acpi_table_parse_entries(char *id,
unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
unsigned int max_entries)
{
struct acpi_subtable_proc proc = {
.id = entry_id,
.handler = handler,
};
return acpi_table_parse_entries_array(id, table_size, &proc, 1,
max_entries);
}
int __init acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler, unsigned int max_entries)
{
return acpi_table_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt), id,
handler, max_entries);
}
/**
* 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,
* run @handler on it.
*
* Return 0 if table found, -errno if not.
*/
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
{
struct acpi_table_header *table = NULL;
if (acpi_disabled)
return -ENODEV;
if (!id || !handler)
return -EINVAL;
if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
acpi_get_table(id, acpi_apic_instance, &table);
else
acpi_get_table(id, 0, &table);
if (table) {
handler(table);
acpi_put_table(table);
return 0;
} else
return -ENODEV;
}
/*
* 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;
acpi_get_table(ACPI_SIG_MADT, 2, &table);
if (table) {
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);
acpi_put_table(table);
} else
acpi_apic_instance = 0;
return;
}
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);
}
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
#ifdef CONFIG_ACPI_TABLE_UPGRADE
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: */
static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = {
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,
ACPI_SIG_NHLT };
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03: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);
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
void __init acpi_table_upgrade(void)
{
void *data;
size_t size;
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;
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;
}
if (data == NULL || size == 0)
return;
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
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;
for (sig = 0; sig < ARRAY_SIZE(table_sigs); sig++)
if (!memcmp(table->signature, table_sigs[sig], 4))
break;
if (sig >= ARRAY_SIZE(table_sigs)) {
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;
if (security_locked_down(LOCKDOWN_ACPI_TABLES)) {
pr_notice("kernel is locked down, ignoring table override\n");
return;
}
acpi_tables_addr =
memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS,
all_tables_size, PAGE_SIZE);
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 16:19:36 +03:00
* Both memblock_reserve and e820__range_add (via arch_reserve_mem_area)
* works fine.
*/
memblock_reserve(acpi_tables_addr, all_tables_size);
arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
/*
* 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;
dest_p = early_memremap(dest_addr & PAGE_MASK,
clen + slop);
memcpy(dest_p + slop, src_p, clen);
early_memunmap(dest_p, clen + slop);
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 */
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
if (memcmp(existing_table->signature, table->signature, 4) ||
memcmp(table->oem_id, existing_table->oem_id,
ACPI_OEM_ID_SIZE) ||
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;
}
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03: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;
}
*length = table_length;
*address = acpi_tables_addr + table_offset;
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n",
table->signature, table->oem_id,
table->oem_table_id);
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 */
if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_RSDT) ||
ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_XSDT)) {
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
goto next_table;
}
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
/*
* Mark the table to avoid being used in
* acpi_table_initrd_override(). Though this is not possible
* because override is disabled in acpi_install_table().
*/
if (test_and_set_bit(table_index, acpi_initrd_installed)) {
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
goto next_table;
}
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n",
table->signature, table->oem_id,
table->oem_table_id);
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
acpi_install_table(acpi_tables_addr + table_offset, TRUE);
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)
{
}
ACPI / tables: Convert initrd table override to table upgrade mechanism This patch converts the initrd table override mechanism to the table upgrade mechanism by restricting its usage to the tables released with compatibility and more recent revision. This use case has been encouraged by the ACPI specification: 1. OEMID: An OEM-supplied string that identifies the OEM. 2. OEM Table ID: An OEM-supplied string that the OEM uses to identify the particular data table. This field is particularly useful when defining a definition block to distinguish definition block functions. OEM assigns each dissimilar table a new OEM Table Id. 3. OEM Revision: An OEM-supplied revision number. Larger numbers are assumed to be newer revisions. For OEMs, good practices will ensure consistency when assigning OEMID and OEM Table ID fields in any table. The intent of these fields is to allow for a binary control system that support services can use. Because many support function can be automated, it is useful when a tool can programatically determine which table release is a compatible and more recent revision of a prior table on the same OEMID and OEM Table ID. The facility can now be used by the vendors to upgrade wrong tables for bug fixing purpose, thus lockdep disabling taint is not suitable for it and it should be a default 'y' option to implement the spec encouraged use case. Note that, by implementing table upgrade inside of ACPICA itself, it is possible to remove acpi_table_initrd_override() and tables can be upgraded by acpi_install_table() automatically. Though current ACPICA impelentation hasn't implemented this, this patched changes the table flag setting timing to allow this to be implemented in ACPICA without changing the code here. Documentation of initrd override mechanism is upgraded accordingly. Original-by: Octavian Purdila <octavian.purdila@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-04-11 05:13:33 +03:00
#endif /* CONFIG_ACPI_TABLE_UPGRADE */
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);
}
#ifdef CONFIG_ACPI_CUSTOM_DSDT
static void *amlcode __attribute__ ((weakref("AmlCode")));
static void *dsdt_amlcode __attribute__ ((weakref("dsdt_aml_code")));
#endif
acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
struct acpi_table_header **new_table)
{
if (!existing_table || !new_table)
return AE_BAD_PARAMETER;
*new_table = NULL;
#ifdef CONFIG_ACPI_CUSTOM_DSDT
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;
}
#endif
if (*new_table != NULL)
acpi_table_taint(existing_table);
return AE_OK;
}
/*
ACPI: tables: x86: Reserve memory occupied by ACPI tables The following problem has been reported by George Kennedy: Since commit 7fef431be9c9 ("mm/page_alloc: place pages to tail in __free_pages_core()") the following use after free occurs intermittently when ACPI tables are accessed. BUG: KASAN: use-after-free in ibft_init+0x134/0xc49 Read of size 4 at addr ffff8880be453004 by task swapper/0/1 CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1-7a7fd0d #1 Call Trace: dump_stack+0xf6/0x158 print_address_description.constprop.9+0x41/0x60 kasan_report.cold.14+0x7b/0xd4 __asan_report_load_n_noabort+0xf/0x20 ibft_init+0x134/0xc49 do_one_initcall+0xc4/0x3e0 kernel_init_freeable+0x5af/0x66b kernel_init+0x16/0x1d0 ret_from_fork+0x22/0x30 ACPI tables mapped via kmap() do not have their mapped pages reserved and the pages can be "stolen" by the buddy allocator. Apparently, on the affected system, the ACPI table in question is not located in "reserved" memory, like ACPI NVS or ACPI Data, that will not be used by the buddy allocator, so the memory occupied by that table has to be explicitly reserved to prevent the buddy allocator from using it. In order to address this problem, rearrange the initialization of the ACPI tables on x86 to locate the initial tables earlier and reserve the memory occupied by them. The other architectures using ACPI should not be affected by this change. Link: https://lore.kernel.org/linux-acpi/1614802160-29362-1-git-send-email-george.kennedy@oracle.com/ Reported-by: George Kennedy <george.kennedy@oracle.com> Tested-by: George Kennedy <george.kennedy@oracle.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Cc: 5.10+ <stable@vger.kernel.org> # 5.10+
2021-03-23 22:26:52 +03:00
* acpi_locate_initial_tables()
*
* find RSDP, find and checksum SDT/XSDT.
* checksum all tables, print SDT/XSDT
*
* result: sdt_entry[] is initialized
*/
ACPI: tables: x86: Reserve memory occupied by ACPI tables The following problem has been reported by George Kennedy: Since commit 7fef431be9c9 ("mm/page_alloc: place pages to tail in __free_pages_core()") the following use after free occurs intermittently when ACPI tables are accessed. BUG: KASAN: use-after-free in ibft_init+0x134/0xc49 Read of size 4 at addr ffff8880be453004 by task swapper/0/1 CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1-7a7fd0d #1 Call Trace: dump_stack+0xf6/0x158 print_address_description.constprop.9+0x41/0x60 kasan_report.cold.14+0x7b/0xd4 __asan_report_load_n_noabort+0xf/0x20 ibft_init+0x134/0xc49 do_one_initcall+0xc4/0x3e0 kernel_init_freeable+0x5af/0x66b kernel_init+0x16/0x1d0 ret_from_fork+0x22/0x30 ACPI tables mapped via kmap() do not have their mapped pages reserved and the pages can be "stolen" by the buddy allocator. Apparently, on the affected system, the ACPI table in question is not located in "reserved" memory, like ACPI NVS or ACPI Data, that will not be used by the buddy allocator, so the memory occupied by that table has to be explicitly reserved to prevent the buddy allocator from using it. In order to address this problem, rearrange the initialization of the ACPI tables on x86 to locate the initial tables earlier and reserve the memory occupied by them. The other architectures using ACPI should not be affected by this change. Link: https://lore.kernel.org/linux-acpi/1614802160-29362-1-git-send-email-george.kennedy@oracle.com/ Reported-by: George Kennedy <george.kennedy@oracle.com> Tested-by: George Kennedy <george.kennedy@oracle.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Cc: 5.10+ <stable@vger.kernel.org> # 5.10+
2021-03-23 22:26:52 +03:00
int __init acpi_locate_initial_tables(void)
{
acpi_status status;
ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [<ffffffff817c627b>] dump_stack+0x45/0x56 [<ffffffff81067b5d>] warn_slowpath_common+0x7d/0xa0 [<ffffffff81067c3a>] warn_slowpath_null+0x1a/0x20 [<ffffffff81d4b9d5>] __early_ioremap+0x11f/0x1f2 [<ffffffff81d4bc5b>] early_ioremap+0x13/0x15 [<ffffffff81d2b8f3>] __acpi_map_table+0x13/0x18 [<ffffffff817b8d1a>] acpi_os_map_memory+0x26/0x14e [<ffffffff813ff018>] acpi_tb_acquire_table+0x42/0x70 [<ffffffff813ff086>] acpi_tb_validate_table+0x27/0x37 [<ffffffff813ff0e5>] acpi_tb_verify_table+0x22/0xd8 [<ffffffff813ff6a8>] acpi_tb_install_non_fixed_table+0x60/0x1c9 [<ffffffff81d61024>] acpi_tb_parse_root_table+0x218/0x26a [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d610cd>] acpi_initialize_tables+0x57/0x59 [<ffffffff81d5f25d>] acpi_table_init+0x1b/0x99 [<ffffffff81d2bca0>] acpi_boot_table_init+0x1e/0x85 [<ffffffff81d23043>] setup_arch+0x99d/0xcc6 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1bbbe>] start_kernel+0x8b/0x415 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1b5ee>] x86_64_start_reservations+0x2a/0x2c [<ffffffff81d1b72e>] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-tested-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-31 04:15:02 +04:00
if (acpi_verify_table_checksum) {
pr_info("Early table checksum verification enabled\n");
acpi_gbl_enable_table_validation = TRUE;
ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [<ffffffff817c627b>] dump_stack+0x45/0x56 [<ffffffff81067b5d>] warn_slowpath_common+0x7d/0xa0 [<ffffffff81067c3a>] warn_slowpath_null+0x1a/0x20 [<ffffffff81d4b9d5>] __early_ioremap+0x11f/0x1f2 [<ffffffff81d4bc5b>] early_ioremap+0x13/0x15 [<ffffffff81d2b8f3>] __acpi_map_table+0x13/0x18 [<ffffffff817b8d1a>] acpi_os_map_memory+0x26/0x14e [<ffffffff813ff018>] acpi_tb_acquire_table+0x42/0x70 [<ffffffff813ff086>] acpi_tb_validate_table+0x27/0x37 [<ffffffff813ff0e5>] acpi_tb_verify_table+0x22/0xd8 [<ffffffff813ff6a8>] acpi_tb_install_non_fixed_table+0x60/0x1c9 [<ffffffff81d61024>] acpi_tb_parse_root_table+0x218/0x26a [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d610cd>] acpi_initialize_tables+0x57/0x59 [<ffffffff81d5f25d>] acpi_table_init+0x1b/0x99 [<ffffffff81d2bca0>] acpi_boot_table_init+0x1e/0x85 [<ffffffff81d23043>] setup_arch+0x99d/0xcc6 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1bbbe>] start_kernel+0x8b/0x415 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1b5ee>] x86_64_start_reservations+0x2a/0x2c [<ffffffff81d1b72e>] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-tested-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-31 04:15:02 +04:00
} else {
pr_info("Early table checksum verification disabled\n");
acpi_gbl_enable_table_validation = FALSE;
ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [<ffffffff817c627b>] dump_stack+0x45/0x56 [<ffffffff81067b5d>] warn_slowpath_common+0x7d/0xa0 [<ffffffff81067c3a>] warn_slowpath_null+0x1a/0x20 [<ffffffff81d4b9d5>] __early_ioremap+0x11f/0x1f2 [<ffffffff81d4bc5b>] early_ioremap+0x13/0x15 [<ffffffff81d2b8f3>] __acpi_map_table+0x13/0x18 [<ffffffff817b8d1a>] acpi_os_map_memory+0x26/0x14e [<ffffffff813ff018>] acpi_tb_acquire_table+0x42/0x70 [<ffffffff813ff086>] acpi_tb_validate_table+0x27/0x37 [<ffffffff813ff0e5>] acpi_tb_verify_table+0x22/0xd8 [<ffffffff813ff6a8>] acpi_tb_install_non_fixed_table+0x60/0x1c9 [<ffffffff81d61024>] acpi_tb_parse_root_table+0x218/0x26a [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d610cd>] acpi_initialize_tables+0x57/0x59 [<ffffffff81d5f25d>] acpi_table_init+0x1b/0x99 [<ffffffff81d2bca0>] acpi_boot_table_init+0x1e/0x85 [<ffffffff81d23043>] setup_arch+0x99d/0xcc6 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1bbbe>] start_kernel+0x8b/0x415 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1b5ee>] x86_64_start_reservations+0x2a/0x2c [<ffffffff81d1b72e>] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-tested-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-31 04:15:02 +04:00
}
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status))
return -EINVAL;
ACPI: tables: x86: Reserve memory occupied by ACPI tables The following problem has been reported by George Kennedy: Since commit 7fef431be9c9 ("mm/page_alloc: place pages to tail in __free_pages_core()") the following use after free occurs intermittently when ACPI tables are accessed. BUG: KASAN: use-after-free in ibft_init+0x134/0xc49 Read of size 4 at addr ffff8880be453004 by task swapper/0/1 CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1-7a7fd0d #1 Call Trace: dump_stack+0xf6/0x158 print_address_description.constprop.9+0x41/0x60 kasan_report.cold.14+0x7b/0xd4 __asan_report_load_n_noabort+0xf/0x20 ibft_init+0x134/0xc49 do_one_initcall+0xc4/0x3e0 kernel_init_freeable+0x5af/0x66b kernel_init+0x16/0x1d0 ret_from_fork+0x22/0x30 ACPI tables mapped via kmap() do not have their mapped pages reserved and the pages can be "stolen" by the buddy allocator. Apparently, on the affected system, the ACPI table in question is not located in "reserved" memory, like ACPI NVS or ACPI Data, that will not be used by the buddy allocator, so the memory occupied by that table has to be explicitly reserved to prevent the buddy allocator from using it. In order to address this problem, rearrange the initialization of the ACPI tables on x86 to locate the initial tables earlier and reserve the memory occupied by them. The other architectures using ACPI should not be affected by this change. Link: https://lore.kernel.org/linux-acpi/1614802160-29362-1-git-send-email-george.kennedy@oracle.com/ Reported-by: George Kennedy <george.kennedy@oracle.com> Tested-by: George Kennedy <george.kennedy@oracle.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Cc: 5.10+ <stable@vger.kernel.org> # 5.10+
2021-03-23 22:26:52 +03: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();
check_multiple_madt();
ACPI: tables: x86: Reserve memory occupied by ACPI tables The following problem has been reported by George Kennedy: Since commit 7fef431be9c9 ("mm/page_alloc: place pages to tail in __free_pages_core()") the following use after free occurs intermittently when ACPI tables are accessed. BUG: KASAN: use-after-free in ibft_init+0x134/0xc49 Read of size 4 at addr ffff8880be453004 by task swapper/0/1 CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.12.0-rc1-7a7fd0d #1 Call Trace: dump_stack+0xf6/0x158 print_address_description.constprop.9+0x41/0x60 kasan_report.cold.14+0x7b/0xd4 __asan_report_load_n_noabort+0xf/0x20 ibft_init+0x134/0xc49 do_one_initcall+0xc4/0x3e0 kernel_init_freeable+0x5af/0x66b kernel_init+0x16/0x1d0 ret_from_fork+0x22/0x30 ACPI tables mapped via kmap() do not have their mapped pages reserved and the pages can be "stolen" by the buddy allocator. Apparently, on the affected system, the ACPI table in question is not located in "reserved" memory, like ACPI NVS or ACPI Data, that will not be used by the buddy allocator, so the memory occupied by that table has to be explicitly reserved to prevent the buddy allocator from using it. In order to address this problem, rearrange the initialization of the ACPI tables on x86 to locate the initial tables earlier and reserve the memory occupied by them. The other architectures using ACPI should not be affected by this change. Link: https://lore.kernel.org/linux-acpi/1614802160-29362-1-git-send-email-george.kennedy@oracle.com/ Reported-by: George Kennedy <george.kennedy@oracle.com> Tested-by: George Kennedy <george.kennedy@oracle.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Cc: 5.10+ <stable@vger.kernel.org> # 5.10+
2021-03-23 22:26:52 +03:00
}
int __init acpi_table_init(void)
{
int ret;
ret = acpi_locate_initial_tables();
if (ret)
return ret;
acpi_table_init_complete();
return 0;
}
static int __init acpi_parse_apic_instance(char *str)
{
if (!str)
return -EINVAL;
if (kstrtoint(str, 0, &acpi_apic_instance))
return -EINVAL;
pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
return 0;
}
early_param("acpi_apic_instance", acpi_parse_apic_instance);
ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [<ffffffff817c627b>] dump_stack+0x45/0x56 [<ffffffff81067b5d>] warn_slowpath_common+0x7d/0xa0 [<ffffffff81067c3a>] warn_slowpath_null+0x1a/0x20 [<ffffffff81d4b9d5>] __early_ioremap+0x11f/0x1f2 [<ffffffff81d4bc5b>] early_ioremap+0x13/0x15 [<ffffffff81d2b8f3>] __acpi_map_table+0x13/0x18 [<ffffffff817b8d1a>] acpi_os_map_memory+0x26/0x14e [<ffffffff813ff018>] acpi_tb_acquire_table+0x42/0x70 [<ffffffff813ff086>] acpi_tb_validate_table+0x27/0x37 [<ffffffff813ff0e5>] acpi_tb_verify_table+0x22/0xd8 [<ffffffff813ff6a8>] acpi_tb_install_non_fixed_table+0x60/0x1c9 [<ffffffff81d61024>] acpi_tb_parse_root_table+0x218/0x26a [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d610cd>] acpi_initialize_tables+0x57/0x59 [<ffffffff81d5f25d>] acpi_table_init+0x1b/0x99 [<ffffffff81d2bca0>] acpi_boot_table_init+0x1e/0x85 [<ffffffff81d23043>] setup_arch+0x99d/0xcc6 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1bbbe>] start_kernel+0x8b/0x415 [<ffffffff81d1b120>] ? early_idt_handlers+0x120/0x120 [<ffffffff81d1b5ee>] x86_64_start_reservations+0x2a/0x2c [<ffffffff81d1b72e>] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-tested-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-31 04:15:02 +04: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);
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);