Skip to content

Commit 5d88132

Browse files
Lv Zhengrafaeljw
authored andcommitted
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 <[email protected]> Signed-off-by: Lv Zheng <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent af06f8b commit 5d88132

File tree

3 files changed

+77
-44
lines changed

3 files changed

+77
-44
lines changed

Documentation/acpi/initrd_table_override.txt

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Overriding ACPI tables via initrd
2-
=================================
1+
Upgrading ACPI tables via initrd
2+
================================
33

44
1) Introduction (What is this about)
55
2) What is this for
@@ -9,12 +9,14 @@ Overriding ACPI tables via initrd
99
1) What is this about
1010
---------------------
1111

12-
If the ACPI_INITRD_TABLE_OVERRIDE compile option is true, it is possible to
13-
override nearly any ACPI table provided by the BIOS with an instrumented,
14-
modified one.
12+
If the ACPI_TABLE_UPGRADE compile option is true, it is possible to
13+
upgrade the ACPI execution environment that is defined by the ACPI tables
14+
via upgrading the ACPI tables provided by the BIOS with an instrumented,
15+
modified, more recent version one, or installing brand new ACPI tables.
1516

16-
For a full list of ACPI tables that can be overridden, take a look at
17-
the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in drivers/acpi/osl.c
17+
For a full list of ACPI tables that can be upgraded/installed, take a look
18+
at the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in
19+
drivers/acpi/tables.c.
1820
All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should
1921
be overridable, except:
2022
- ACPI_SIG_RSDP (has a signature of 6 bytes)
@@ -25,17 +27,20 @@ Both could get implemented as well.
2527
2) What is this for
2628
-------------------
2729

28-
Please keep in mind that this is a debug option.
29-
ACPI tables should not get overridden for productive use.
30-
If BIOS ACPI tables are overridden the kernel will get tainted with the
31-
TAINT_OVERRIDDEN_ACPI_TABLE flag.
32-
Complain to your platform/BIOS vendor if you find a bug which is so sever
33-
that a workaround is not accepted in the Linux kernel.
30+
Complain to your platform/BIOS vendor if you find a bug which is so severe
31+
that a workaround is not accepted in the Linux kernel. And this facility
32+
allows you to upgrade the buggy tables before your platform/BIOS vendor
33+
releases an upgraded BIOS binary.
3434

35-
Still, it can and should be enabled in any kernel, because:
36-
- There is no functional change with not instrumented initrds
37-
- It provides a powerful feature to easily debug and test ACPI BIOS table
38-
compatibility with the Linux kernel.
35+
This facility can be used by platform/BIOS vendors to provide a Linux
36+
compatible environment without modifying the underlying platform firmware.
37+
38+
This facility also provides a powerful feature to easily debug and test
39+
ACPI BIOS table compatibility with the Linux kernel by modifying old
40+
platform provided ACPI tables or inserting new ACPI tables.
41+
42+
It can and should be enabled in any kernel because there is no functional
43+
change with not instrumented initrds.
3944

4045

4146
3) How does it work
@@ -50,23 +55,31 @@ iasl -d *.dat
5055
# For example add this statement into a _PRT (PCI Routing Table) function
5156
# of the DSDT:
5257
Store("HELLO WORLD", debug)
58+
# And increase the OEM Revision. For example, before modification:
59+
DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000)
60+
# After modification:
61+
DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001)
5362
iasl -sa dsdt.dsl
5463
# Add the raw ACPI tables to an uncompressed cpio archive.
55-
# They must be put into a /kernel/firmware/acpi directory inside the
56-
# cpio archive.
57-
# The uncompressed cpio archive must be the first.
58-
# Other, typically compressed cpio archives, must be
59-
# concatenated on top of the uncompressed one.
64+
# They must be put into a /kernel/firmware/acpi directory inside the cpio
65+
# archive. Note that if the table put here matches a platform table
66+
# (similar Table Signature, and similar OEMID, and similar OEM Table ID)
67+
# with a more recent OEM Revision, the platform table will be upgraded by
68+
# this table. If the table put here doesn't match a platform table
69+
# (dissimilar Table Signature, or dissimilar OEMID, or dissimilar OEM Table
70+
# ID), this table will be appended.
6071
mkdir -p kernel/firmware/acpi
6172
cp dsdt.aml kernel/firmware/acpi
62-
# A maximum of: #define ACPI_OVERRIDE_TABLES 10
63-
# tables are currently allowed (see osl.c):
73+
# A maximum of "NR_ACPI_INITRD_TABLES (64)" tables are currently allowed
74+
# (see osl.c):
6475
iasl -sa facp.dsl
6576
iasl -sa ssdt1.dsl
6677
cp facp.aml kernel/firmware/acpi
6778
cp ssdt1.aml kernel/firmware/acpi
68-
# Create the uncompressed cpio archive and concatenate the original initrd
69-
# on top:
79+
# The uncompressed cpio archive must be the first. Other, typically
80+
# compressed cpio archives, must be concatenated on top of the uncompressed
81+
# one. Following command creates the uncompressed cpio archive and
82+
# concatenates the original initrd on top:
7083
find kernel | cpio -H newc --create > /boot/instrumented_initrd
7184
cat /boot/initrd >>/boot/instrumented_initrd
7285
# reboot with increased acpi debug level, e.g. boot params:

drivers/acpi/Kconfig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,12 @@ config ACPI_CUSTOM_DSDT
311311
bool
312312
default ACPI_CUSTOM_DSDT_FILE != ""
313313

314-
config ACPI_INITRD_TABLE_OVERRIDE
315-
bool "ACPI tables override via initrd"
314+
config ACPI_TABLE_UPGRADE
315+
bool "Allow upgrading ACPI tables via initrd"
316316
depends on BLK_DEV_INITRD && X86
317-
default n
317+
default y
318318
help
319-
This option provides functionality to override arbitrary ACPI tables
319+
This option provides functionality to upgrade arbitrary ACPI tables
320320
via initrd. No functional change if no ACPI tables are passed via
321321
initrd, therefore it's safe to say Y.
322322
See Documentation/acpi/initrd_table_override.txt for details

drivers/acpi/tables.c

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ static void acpi_table_taint(struct acpi_table_header *table)
442442
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
443443
}
444444

445-
#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
445+
#ifdef CONFIG_ACPI_TABLE_UPGRADE
446446
static u64 acpi_tables_addr;
447447
static int all_tables_size;
448448

@@ -471,9 +471,9 @@ static const char * const table_sigs[] = {
471471

472472
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
473473

474-
#define ACPI_OVERRIDE_TABLES 64
475-
static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES];
476-
static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES);
474+
#define NR_ACPI_INITRD_TABLES 64
475+
static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES];
476+
static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
477477

478478
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
479479

@@ -488,7 +488,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size)
488488
if (data == NULL || size == 0)
489489
return;
490490

491-
for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
491+
for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
492492
file = find_cpio_data(cpio_path, data, size, &offset);
493493
if (!file.data)
494494
break;
@@ -611,19 +611,30 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
611611
table_length = table->length;
612612

613613
/* Only override tables matched */
614-
if (test_bit(table_index, acpi_initrd_installed) ||
615-
memcmp(existing_table->signature, table->signature, 4) ||
614+
if (memcmp(existing_table->signature, table->signature, 4) ||
615+
memcmp(table->oem_id, existing_table->oem_id,
616+
ACPI_OEM_ID_SIZE) ||
616617
memcmp(table->oem_table_id, existing_table->oem_table_id,
617618
ACPI_OEM_TABLE_ID_SIZE)) {
618619
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
619620
goto next_table;
620621
}
622+
/*
623+
* Mark the table to avoid being used in
624+
* acpi_table_initrd_scan() and check the revision.
625+
*/
626+
if (test_and_set_bit(table_index, acpi_initrd_installed) ||
627+
existing_table->oem_revision >= table->oem_revision) {
628+
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
629+
goto next_table;
630+
}
621631

622632
*length = table_length;
623633
*address = acpi_tables_addr + table_offset;
624-
acpi_table_taint(existing_table);
634+
pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n",
635+
table->signature, table->oem_id,
636+
table->oem_table_id);
625637
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
626-
set_bit(table_index, acpi_initrd_installed);
627638
break;
628639

629640
next_table:
@@ -655,17 +666,26 @@ static void __init acpi_table_initrd_scan(void)
655666
table_length = table->length;
656667

657668
/* Skip RSDT/XSDT which should only be used for override */
658-
if (test_bit(table_index, acpi_initrd_installed) ||
659-
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
669+
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
660670
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
661671
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
662672
goto next_table;
663673
}
674+
/*
675+
* Mark the table to avoid being used in
676+
* acpi_table_initrd_override(). Though this is not possible
677+
* because override is disabled in acpi_install_table().
678+
*/
679+
if (test_and_set_bit(table_index, acpi_initrd_installed)) {
680+
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
681+
goto next_table;
682+
}
664683

665-
acpi_table_taint(table);
684+
pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n",
685+
table->signature, table->oem_id,
686+
table->oem_table_id);
666687
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
667688
acpi_install_table(acpi_tables_addr + table_offset, TRUE);
668-
set_bit(table_index, acpi_initrd_installed);
669689
next_table:
670690
table_offset += table_length;
671691
table_index++;
@@ -689,7 +709,7 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
689709
static void __init acpi_table_initrd_scan(void)
690710
{
691711
}
692-
#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
712+
#endif /* CONFIG_ACPI_TABLE_UPGRADE */
693713

694714
acpi_status
695715
acpi_os_physical_table_override(struct acpi_table_header *existing_table,

0 commit comments

Comments
 (0)