diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-04-10 22:13:33 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-04-18 17:59:09 -0400 |
commit | 5d8813271f8a7c86027afb2ef554f2a5a9ba7c15 (patch) | |
tree | 75e3ea3cafe1b4be9ce00a7352ce75ca0c9fb7a4 | |
parent | af06f8b7a102417e93dc57ee7affb9fedcf5d83f (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.txt | 65 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/acpi/tables.c | 48 |
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 @@ | |||
1 | Overriding ACPI tables via initrd | 1 | Upgrading ACPI tables via initrd |
2 | ================================= | 2 | ================================ |
3 | 3 | ||
4 | 1) Introduction (What is this about) | 4 | 1) Introduction (What is this about) |
5 | 2) What is this for | 5 | 2) What is this for |
@@ -9,12 +9,14 @@ Overriding ACPI tables via initrd | |||
9 | 1) What is this about | 9 | 1) What is this about |
10 | --------------------- | 10 | --------------------- |
11 | 11 | ||
12 | If the ACPI_INITRD_TABLE_OVERRIDE compile option is true, it is possible to | 12 | If the ACPI_TABLE_UPGRADE compile option is true, it is possible to |
13 | override nearly any ACPI table provided by the BIOS with an instrumented, | 13 | upgrade the ACPI execution environment that is defined by the ACPI tables |
14 | modified one. | 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. | ||
15 | 16 | ||
16 | For a full list of ACPI tables that can be overridden, take a look at | 17 | For a full list of ACPI tables that can be upgraded/installed, take a look |
17 | the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in drivers/acpi/osl.c | 18 | at the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in |
19 | drivers/acpi/tables.c. | ||
18 | All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should | 20 | All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should |
19 | be overridable, except: | 21 | be 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. | |||
25 | 2) What is this for | 27 | 2) What is this for |
26 | ------------------- | 28 | ------------------- |
27 | 29 | ||
28 | Please keep in mind that this is a debug option. | 30 | Complain to your platform/BIOS vendor if you find a bug which is so severe |
29 | ACPI tables should not get overridden for productive use. | 31 | that a workaround is not accepted in the Linux kernel. And this facility |
30 | If BIOS ACPI tables are overridden the kernel will get tainted with the | 32 | allows you to upgrade the buggy tables before your platform/BIOS vendor |
31 | TAINT_OVERRIDDEN_ACPI_TABLE flag. | 33 | releases an upgraded BIOS binary. |
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. | ||
34 | 34 | ||
35 | Still, it can and should be enabled in any kernel, because: | 35 | This facility can be used by platform/BIOS vendors to provide a Linux |
36 | - There is no functional change with not instrumented initrds | 36 | compatible 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. | 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. | ||
39 | 44 | ||
40 | 45 | ||
41 | 3) How does it work | 46 | 3) 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: |
52 | Store("HELLO WORLD", debug) | 57 | 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) | ||
53 | iasl -sa dsdt.dsl | 62 | iasl -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. | ||
60 | mkdir -p kernel/firmware/acpi | 71 | mkdir -p kernel/firmware/acpi |
61 | cp dsdt.aml kernel/firmware/acpi | 72 | cp 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): |
64 | iasl -sa facp.dsl | 75 | iasl -sa facp.dsl |
65 | iasl -sa ssdt1.dsl | 76 | iasl -sa ssdt1.dsl |
66 | cp facp.aml kernel/firmware/acpi | 77 | cp facp.aml kernel/firmware/acpi |
67 | cp ssdt1.aml kernel/firmware/acpi | 78 | cp 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: | ||
70 | find kernel | cpio -H newc --create > /boot/instrumented_initrd | 83 | find kernel | cpio -H newc --create > /boot/instrumented_initrd |
71 | cat /boot/initrd >>/boot/instrumented_initrd | 84 | cat /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 | ||
314 | config ACPI_INITRD_TABLE_OVERRIDE | 314 | config 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 |
446 | static u64 acpi_tables_addr; | 446 | static u64 acpi_tables_addr; |
447 | static int all_tables_size; | 447 | static 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 |
475 | static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES]; | 475 | static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES]; |
476 | static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES); | 476 | static 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 | ||
629 | next_table: | 640 | next_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); | ||
669 | next_table: | 689 | next_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, | |||
689 | static void __init acpi_table_initrd_scan(void) | 709 | static 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 | ||
694 | acpi_status | 714 | acpi_status |
695 | acpi_os_physical_table_override(struct acpi_table_header *existing_table, | 715 | acpi_os_physical_table_override(struct acpi_table_header *existing_table, |