aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-04-10 22:13:33 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-04-18 17:59:09 -0400
commit5d8813271f8a7c86027afb2ef554f2a5a9ba7c15 (patch)
tree75e3ea3cafe1b4be9ce00a7352ce75ca0c9fb7a4
parentaf06f8b7a102417e93dc57ee7affb9fedcf5d83f (diff)
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>
-rw-r--r--Documentation/acpi/initrd_table_override.txt65
-rw-r--r--drivers/acpi/Kconfig8
-rw-r--r--drivers/acpi/tables.c48
3 files changed, 77 insertions, 44 deletions
diff --git a/Documentation/acpi/initrd_table_override.txt b/Documentation/acpi/initrd_table_override.txt
index 35c3f5415476..eb651a6aa285 100644
--- a/Documentation/acpi/initrd_table_override.txt
+++ b/Documentation/acpi/initrd_table_override.txt
@@ -1,5 +1,5 @@
1Overriding ACPI tables via initrd 1Upgrading ACPI tables via initrd
2================================= 2================================
3 3
41) Introduction (What is this about) 41) Introduction (What is this about)
52) What is this for 52) What is this for
@@ -9,12 +9,14 @@ Overriding ACPI tables via initrd
91) What is this about 91) What is this about
10--------------------- 10---------------------
11 11
12If the ACPI_INITRD_TABLE_OVERRIDE compile option is true, it is possible to 12If the ACPI_TABLE_UPGRADE compile option is true, it is possible to
13override nearly any ACPI table provided by the BIOS with an instrumented, 13upgrade the ACPI execution environment that is defined by the ACPI tables
14modified one. 14via upgrading the ACPI tables provided by the BIOS with an instrumented,
15modified, more recent version one, or installing brand new ACPI tables.
15 16
16For a full list of ACPI tables that can be overridden, take a look at 17For a full list of ACPI tables that can be upgraded/installed, take a look
17the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in drivers/acpi/osl.c 18at the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in
19drivers/acpi/tables.c.
18All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should 20All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should
19be overridable, except: 21be overridable, except:
20 - ACPI_SIG_RSDP (has a signature of 6 bytes) 22 - ACPI_SIG_RSDP (has a signature of 6 bytes)
@@ -25,17 +27,20 @@ Both could get implemented as well.
252) What is this for 272) What is this for
26------------------- 28-------------------
27 29
28Please keep in mind that this is a debug option. 30Complain to your platform/BIOS vendor if you find a bug which is so severe
29ACPI tables should not get overridden for productive use. 31that a workaround is not accepted in the Linux kernel. And this facility
30If BIOS ACPI tables are overridden the kernel will get tainted with the 32allows you to upgrade the buggy tables before your platform/BIOS vendor
31TAINT_OVERRIDDEN_ACPI_TABLE flag. 33releases an upgraded BIOS binary.
32Complain to your platform/BIOS vendor if you find a bug which is so sever
33that a workaround is not accepted in the Linux kernel.
34 34
35Still, it can and should be enabled in any kernel, because: 35This facility can be used by platform/BIOS vendors to provide a Linux
36 - There is no functional change with not instrumented initrds 36compatible environment without modifying the underlying platform firmware.
37 - It provides a powerful feature to easily debug and test ACPI BIOS table 37
38 compatibility with the Linux kernel. 38This facility also provides a powerful feature to easily debug and test
39ACPI BIOS table compatibility with the Linux kernel by modifying old
40platform provided ACPI tables or inserting new ACPI tables.
41
42It can and should be enabled in any kernel because there is no functional
43change with not instrumented initrds.
39 44
40 45
413) How does it work 463) How does it work
@@ -50,23 +55,31 @@ iasl -d *.dat
50# For example add this statement into a _PRT (PCI Routing Table) function 55# For example add this statement into a _PRT (PCI Routing Table) function
51# of the DSDT: 56# of the DSDT:
52Store("HELLO WORLD", debug) 57Store("HELLO WORLD", debug)
58# And increase the OEM Revision. For example, before modification:
59DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000)
60# After modification:
61DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001)
53iasl -sa dsdt.dsl 62iasl -sa dsdt.dsl
54# Add the raw ACPI tables to an uncompressed cpio archive. 63# Add the raw ACPI tables to an uncompressed cpio archive.
55# They must be put into a /kernel/firmware/acpi directory inside the 64# They must be put into a /kernel/firmware/acpi directory inside the cpio
56# cpio archive. 65# archive. Note that if the table put here matches a platform table
57# The uncompressed cpio archive must be the first. 66# (similar Table Signature, and similar OEMID, and similar OEM Table ID)
58# Other, typically compressed cpio archives, must be 67# with a more recent OEM Revision, the platform table will be upgraded by
59# concatenated on top of the uncompressed one. 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.
60mkdir -p kernel/firmware/acpi 71mkdir -p kernel/firmware/acpi
61cp dsdt.aml kernel/firmware/acpi 72cp dsdt.aml kernel/firmware/acpi
62# A maximum of: #define ACPI_OVERRIDE_TABLES 10 73# A maximum of "NR_ACPI_INITRD_TABLES (64)" tables are currently allowed
63# tables are currently allowed (see osl.c): 74# (see osl.c):
64iasl -sa facp.dsl 75iasl -sa facp.dsl
65iasl -sa ssdt1.dsl 76iasl -sa ssdt1.dsl
66cp facp.aml kernel/firmware/acpi 77cp facp.aml kernel/firmware/acpi
67cp ssdt1.aml kernel/firmware/acpi 78cp ssdt1.aml kernel/firmware/acpi
68# Create the uncompressed cpio archive and concatenate the original initrd 79# The uncompressed cpio archive must be the first. Other, typically
69# on top: 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:
70find kernel | cpio -H newc --create > /boot/instrumented_initrd 83find kernel | cpio -H newc --create > /boot/instrumented_initrd
71cat /boot/initrd >>/boot/instrumented_initrd 84cat /boot/initrd >>/boot/instrumented_initrd
72# reboot with increased acpi debug level, e.g. boot params: 85# reboot with increased acpi debug level, e.g. boot params:
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee8624c..b225c4b9ba14 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -311,12 +311,12 @@ config ACPI_CUSTOM_DSDT
311 bool 311 bool
312 default ACPI_CUSTOM_DSDT_FILE != "" 312 default ACPI_CUSTOM_DSDT_FILE != ""
313 313
314config ACPI_INITRD_TABLE_OVERRIDE 314config ACPI_TABLE_UPGRADE
315 bool "ACPI tables override via initrd" 315 bool "Allow upgrading ACPI tables via initrd"
316 depends on BLK_DEV_INITRD && X86 316 depends on BLK_DEV_INITRD && X86
317 default n 317 default y
318 help 318 help
319 This option provides functionality to override arbitrary ACPI tables 319 This option provides functionality to upgrade arbitrary ACPI tables
320 via initrd. No functional change if no ACPI tables are passed via 320 via initrd. No functional change if no ACPI tables are passed via
321 initrd, therefore it's safe to say Y. 321 initrd, therefore it's safe to say Y.
322 See Documentation/acpi/initrd_table_override.txt for details 322 See Documentation/acpi/initrd_table_override.txt for details
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 2e74dbf45dd4..08795fbde3fa 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -442,7 +442,7 @@ static void acpi_table_taint(struct acpi_table_header *table)
442 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); 442 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
443} 443}
444 444
445#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE 445#ifdef CONFIG_ACPI_TABLE_UPGRADE
446static u64 acpi_tables_addr; 446static u64 acpi_tables_addr;
447static int all_tables_size; 447static int all_tables_size;
448 448
@@ -471,9 +471,9 @@ static const char * const table_sigs[] = {
471 471
472#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) 472#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
473 473
474#define ACPI_OVERRIDE_TABLES 64 474#define NR_ACPI_INITRD_TABLES 64
475static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES]; 475static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES];
476static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES); 476static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
477 477
478#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) 478#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
479 479
@@ -488,7 +488,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size)
488 if (data == NULL || size == 0) 488 if (data == NULL || size == 0)
489 return; 489 return;
490 490
491 for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) { 491 for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) {
492 file = find_cpio_data(cpio_path, data, size, &offset); 492 file = find_cpio_data(cpio_path, data, size, &offset);
493 if (!file.data) 493 if (!file.data)
494 break; 494 break;
@@ -611,19 +611,30 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
611 table_length = table->length; 611 table_length = table->length;
612 612
613 /* Only override tables matched */ 613 /* Only override tables matched */
614 if (test_bit(table_index, acpi_initrd_installed) || 614 if (memcmp(existing_table->signature, table->signature, 4) ||
615 memcmp(existing_table->signature, table->signature, 4) || 615 memcmp(table->oem_id, existing_table->oem_id,
616 ACPI_OEM_ID_SIZE) ||
616 memcmp(table->oem_table_id, existing_table->oem_table_id, 617 memcmp(table->oem_table_id, existing_table->oem_table_id,
617 ACPI_OEM_TABLE_ID_SIZE)) { 618 ACPI_OEM_TABLE_ID_SIZE)) {
618 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 619 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
619 goto next_table; 620 goto next_table;
620 } 621 }
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 }
621 631
622 *length = table_length; 632 *length = table_length;
623 *address = acpi_tables_addr + table_offset; 633 *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);
625 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 637 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
626 set_bit(table_index, acpi_initrd_installed);
627 break; 638 break;
628 639
629next_table: 640next_table:
@@ -655,17 +666,26 @@ static void __init acpi_table_initrd_scan(void)
655 table_length = table->length; 666 table_length = table->length;
656 667
657 /* Skip RSDT/XSDT which should only be used for override */ 668 /* Skip RSDT/XSDT which should only be used for override */
658 if (test_bit(table_index, acpi_initrd_installed) || 669 if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
659 ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
660 ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { 670 ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
661 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 671 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
662 goto next_table; 672 goto next_table;
663 } 673 }
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 }
664 683
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);
666 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 687 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
667 acpi_install_table(acpi_tables_addr + table_offset, TRUE); 688 acpi_install_table(acpi_tables_addr + table_offset, TRUE);
668 set_bit(table_index, acpi_initrd_installed);
669next_table: 689next_table:
670 table_offset += table_length; 690 table_offset += table_length;
671 table_index++; 691 table_index++;
@@ -689,7 +709,7 @@ acpi_table_initrd_override(struct acpi_table_header *existing_table,
689static void __init acpi_table_initrd_scan(void) 709static void __init acpi_table_initrd_scan(void)
690{ 710{
691} 711}
692#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ 712#endif /* CONFIG_ACPI_TABLE_UPGRADE */
693 713
694acpi_status 714acpi_status
695acpi_os_physical_table_override(struct acpi_table_header *existing_table, 715acpi_os_physical_table_override(struct acpi_table_header *existing_table,