Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Lv Zheng and committed by
Rafael J. Wysocki
5d881327 af06f8b7

+77 -44
+39 -26
Documentation/acpi/initrd_table_override.txt
··· 1 - Overriding ACPI tables via initrd 2 - ================================= 1 + Upgrading ACPI tables via initrd 2 + ================================ 3 3 4 4 1) Introduction (What is this about) 5 5 2) What is this for ··· 9 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 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. 15 16 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. 18 20 All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should 19 21 be overridable, except: 20 22 - ACPI_SIG_RSDP (has a signature of 6 bytes) ··· 27 25 2) What is this for 28 26 ------------------- 29 27 30 - Please keep in mind that this is a debug option. 31 - ACPI tables should not get overridden for productive use. 32 - If BIOS ACPI tables are overridden the kernel will get tainted with the 33 - TAINT_OVERRIDDEN_ACPI_TABLE flag. 34 - Complain to your platform/BIOS vendor if you find a bug which is so sever 35 - that a workaround is not accepted in the Linux kernel. 28 + Complain to your platform/BIOS vendor if you find a bug which is so severe 29 + that a workaround is not accepted in the Linux kernel. And this facility 30 + allows you to upgrade the buggy tables before your platform/BIOS vendor 31 + releases an upgraded BIOS binary. 36 32 37 - Still, it can and should be enabled in any kernel, because: 38 - - There is no functional change with not instrumented initrds 39 - - It provides a powerful feature to easily debug and test ACPI BIOS table 40 - compatibility with the Linux kernel. 33 + This facility can be used by platform/BIOS vendors to provide a Linux 34 + compatible environment without modifying the underlying platform firmware. 35 + 36 + This facility also provides a powerful feature to easily debug and test 37 + ACPI BIOS table compatibility with the Linux kernel by modifying old 38 + platform provided ACPI tables or inserting new ACPI tables. 39 + 40 + It can and should be enabled in any kernel because there is no functional 41 + change with not instrumented initrds. 41 42 42 43 43 44 3) How does it work ··· 55 50 # For example add this statement into a _PRT (PCI Routing Table) function 56 51 # of the DSDT: 57 52 Store("HELLO WORLD", debug) 53 + # And increase the OEM Revision. For example, before modification: 54 + DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000) 55 + # After modification: 56 + DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001) 58 57 iasl -sa dsdt.dsl 59 58 # Add the raw ACPI tables to an uncompressed cpio archive. 60 - # They must be put into a /kernel/firmware/acpi directory inside the 61 - # cpio archive. 62 - # The uncompressed cpio archive must be the first. 63 - # Other, typically compressed cpio archives, must be 64 - # concatenated on top of the uncompressed one. 59 + # They must be put into a /kernel/firmware/acpi directory inside the cpio 60 + # archive. Note that if the table put here matches a platform table 61 + # (similar Table Signature, and similar OEMID, and similar OEM Table ID) 62 + # with a more recent OEM Revision, the platform table will be upgraded by 63 + # this table. If the table put here doesn't match a platform table 64 + # (dissimilar Table Signature, or dissimilar OEMID, or dissimilar OEM Table 65 + # ID), this table will be appended. 65 66 mkdir -p kernel/firmware/acpi 66 67 cp dsdt.aml kernel/firmware/acpi 67 - # A maximum of: #define ACPI_OVERRIDE_TABLES 10 68 - # tables are currently allowed (see osl.c): 68 + # A maximum of "NR_ACPI_INITRD_TABLES (64)" tables are currently allowed 69 + # (see osl.c): 69 70 iasl -sa facp.dsl 70 71 iasl -sa ssdt1.dsl 71 72 cp facp.aml kernel/firmware/acpi 72 73 cp ssdt1.aml kernel/firmware/acpi 73 - # Create the uncompressed cpio archive and concatenate the original initrd 74 - # on top: 74 + # The uncompressed cpio archive must be the first. Other, typically 75 + # compressed cpio archives, must be concatenated on top of the uncompressed 76 + # one. Following command creates the uncompressed cpio archive and 77 + # concatenates the original initrd on top: 75 78 find kernel | cpio -H newc --create > /boot/instrumented_initrd 76 79 cat /boot/initrd >>/boot/instrumented_initrd 77 80 # reboot with increased acpi debug level, e.g. boot params:
+4 -4
drivers/acpi/Kconfig
··· 311 311 bool 312 312 default ACPI_CUSTOM_DSDT_FILE != "" 313 313 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" 316 316 depends on BLK_DEV_INITRD && X86 317 - default n 317 + default y 318 318 help 319 - This option provides functionality to override arbitrary ACPI tables 319 + This option provides functionality to upgrade arbitrary ACPI tables 320 320 via initrd. No functional change if no ACPI tables are passed via 321 321 initrd, therefore it's safe to say Y. 322 322 See Documentation/acpi/initrd_table_override.txt for details
+34 -14
drivers/acpi/tables.c
··· 442 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 446 static u64 acpi_tables_addr; 447 447 static int all_tables_size; 448 448 ··· 471 471 472 472 #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) 473 473 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); 477 477 478 478 #define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) 479 479 ··· 488 488 if (data == NULL || size == 0) 489 489 return; 490 490 491 - for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) { 491 + for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) { 492 492 file = find_cpio_data(cpio_path, data, size, &offset); 493 493 if (!file.data) 494 494 break; ··· 611 611 table_length = table->length; 612 612 613 613 /* 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) || 616 617 memcmp(table->oem_table_id, existing_table->oem_table_id, 617 618 ACPI_OEM_TABLE_ID_SIZE)) { 619 + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 620 + goto next_table; 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) { 618 628 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 619 629 goto next_table; 620 630 } 621 631 622 632 *length = table_length; 623 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 637 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 626 - set_bit(table_index, acpi_initrd_installed); 627 638 break; 628 639 629 640 next_table: ··· 666 655 table_length = table->length; 667 656 668 657 /* Skip RSDT/XSDT which should only be used for override */ 669 - if (test_bit(table_index, acpi_initrd_installed) || 670 - ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || 658 + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || 671 659 ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { 672 660 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 673 661 goto next_table; 674 662 } 663 + /* 664 + * Mark the table to avoid being used in 665 + * acpi_table_initrd_override(). Though this is not possible 666 + * because override is disabled in acpi_install_table(). 667 + */ 668 + if (test_and_set_bit(table_index, acpi_initrd_installed)) { 669 + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 670 + goto next_table; 671 + } 675 672 676 - acpi_table_taint(table); 673 + pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n", 674 + table->signature, table->oem_id, 675 + table->oem_table_id); 677 676 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 678 677 acpi_install_table(acpi_tables_addr + table_offset, TRUE); 679 - set_bit(table_index, acpi_initrd_installed); 680 678 next_table: 681 679 table_offset += table_length; 682 680 table_index++; ··· 709 689 static void __init acpi_table_initrd_scan(void) 710 690 { 711 691 } 712 - #endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ 692 + #endif /* CONFIG_ACPI_TABLE_UPGRADE */ 713 693 714 694 acpi_status 715 695 acpi_os_physical_table_override(struct acpi_table_header *existing_table,