ACPI / tables: Add table upgrade mechanism
Subsystems (3)
A message that is not in the archive (sent off-list or not yet received): 273fd92043ff4972a71a94efdf01b67ee4638131
v2 cover ACPI / tables: Add table upgrade mechanism
This patch introduces a table upgrade mechanism based on the existing initrd table override mechanism.
Updated due to a build error reported against early_acpi_table_init() stub.
Lv Zheng (3):
ACPI / tables: Move table override mechanisms to tables.c ACPI / x86: Cleanup initrd related code
ACPI / tables: Convert the initrd table override mechanisms to the
table upgrade mechanism
Documentation/acpi/initrd_table_override.txt | 65 +++--- arch/x86/kernel/setup.c | 12 +- drivers/acpi/Kconfig | 8 +- drivers/acpi/internal.h | 1 - drivers/acpi/osl.c | 274 ---------------------- drivers/acpi/tables.c | 312 +++++++++++++++++++++++++- include/linux/acpi.h | 10 +- 7 files changed, 365 insertions(+), 317 deletions(-)
Signature · 1 line
1.7.10
PATCH v2 1/3 ACPI / tables: Move table override mechanisms to tables.c
This patch moves acpi_os_table_override() andacpi_os_physical_table_override() to tables.c.
Along with the mechanisms, acpi_initrd_initialize_tables() is also moved to tables.c to form a static function. The following functions are renamed according to this change:
1. acpi_initrd_override() -> renamed to early_acpi_table_init(), which invokes acpi_table_initrd_init()
2. acpi_os_physical_table_override() -> which invokes acpi_table_initrd_override()
3. acpi_initialize_initrd_tables() -> renamed to acpi_table_initrd_scan()
--- arch/x86/kernel/setup.c | 2 +- drivers/acpi/internal.h | 1 - drivers/acpi/osl.c | 274 -------------------------------------------- drivers/acpi/tables.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++- include/linux/acpi.h | 10 +- 5 files changed, 294 insertions(+), 285 deletions(-)
arch/x86/kernel/setup.c +1 -1
@@ -1139,7 +1139,7 @@ void __init setup_arch(char **cmdline_p)reserve_initrd ();#if defined(CONFIG_ACPI ) && defined(CONFIG_BLK_DEV_INITRD ) -acpi_initrd_override ((void *)initrd_start, initrd_end - initrd_start); +early_acpi_table_init ((void *)initrd_start, initrd_end - initrd_start);#endif vsmp_init ();
drivers/acpi/internal.h +0 -1
@@ -20,7 +20,6 @@#define PREFIX "ACPI: " -void acpi_initrd_initialize_tables (void );acpi_status acpi_os_initialize1 (void );void init_acpi_device_notify (void );int acpi_scan_init (void );
drivers/acpi/osl.c +0 -274
280 lines not on this page · raw message
drivers/acpi/tables.c +291 -1
310 lines not on this page · raw message
include/linux/acpi.h +2 -8
@@ -190,14 +190,6 @@ static inline int acpi_debugger_notify_command_complete(void) }#endif -#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE -void acpi_initrd_override (void *data,size_t size); -#else -static inline void acpi_initrd_override (void *data,size_t size) -{ -} -#endif -#define BAD_MADT_ENTRY (entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
@@ -216,6 +208,7 @@ void acpi_boot_table_init (void);int acpi_mps_check (void );int acpi_numa_init (void ); +void early_acpi_table_init (void *data,size_t size);int acpi_table_init (void );int acpi_table_parse (char *id,acpi_tbl_table_handler handler); int __init acpi_parse_entries(char *id, unsigned long table_size,
@@ -596,6 +589,7 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)return NULL ; } +static inline void early_acpi_table_init (void *data,size_t size) { }static inline void acpi_early_init (void ) { }static inline void acpi_subsystem_init (void ) { }
Signature · 1 line
1.7.10
PATCH v2 2/3 ACPI / x86: Cleanup initrd related code
In reply to Lv ZhengIn arch/x86/kernel/setup.c, the #ifdef kept for CONFIG_ACPI actually is related to the accessibility of initrd_start/initrd_end, so the stub should be provided from this source file and should only be dependent on CONFIG_BLK_DEV_INITRD.
Note that when ACPI=n and BLK_DEV_INITRD=y, early_initrd_acpi_init() is still a stub because of the stub prepared for early_acpi_table_init().
--- arch/x86/kernel/setup.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/kernel/setup.c +9 -3
@@ -398,6 +398,11 @@ static void __init reserve_initrd(void) memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); } + +static void __init early_initrd_acpi_init (void ) +{ +early_acpi_table_init ((void *)initrd_start, initrd_end - initrd_start); +}#else static void __init early_reserve_initrd (void ) {
@@ -405,6 +410,9 @@ static void __init early_reserve_initrd(void)static void __init reserve_initrd (void ) { } +static void __init early_initrd_acpi_init (void ) +{ +}#endif /* CONFIG_BLK_DEV_INITRD */ static void __init parse_setup_data (void )
@@ -1138,9 +1146,7 @@ void __init setup_arch(char **cmdline_p)reserve_initrd (); -#if defined(CONFIG_ACPI ) && defined(CONFIG_BLK_DEV_INITRD ) -early_acpi_table_init ((void *)initrd_start, initrd_end - initrd_start); -#endif +early_initrd_acpi_init ();vsmp_init ();
Signature · 1 line
1.7.10
PATCH v2 3/3 ACPI / tables: Convert the initrd table override mechanisms to the table upgrade mechanism
In reply to Lv ZhengThis 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.
--- Documentation/acpi/initrd_table_override.txt | 65 +++++++++++++++----------- drivers/acpi/Kconfig | 8 ++-- drivers/acpi/tables.c | 48 +++++++++++++------ 3 files changed, 77 insertions(+), 44 deletions(-)
Documentation/acpi/initrd_table_override.txt +39 -26
@@ -1,5 +1,5 @@ -Overriding ACPI tables via initrd -================================= +Upgrading ACPI tables via initrd +================================ 1) Introduction (What is this about) 2) What is this for
@@ -9,12 +9,14 @@ Overriding ACPI tables via initrd 1) What is this about --------------------- -If the ACPI_INITRD_TABLE_OVERRIDE compile option is true, it is possible to -override nearly any ACPI table provided by the BIOS with an instrumented, -modified one. +If the ACPI_TABLE_UPGRADE compile option is true, it is possible to +upgrade the ACPI execution environment that is defined by the ACPI tables +via upgrading the ACPI tables provided by the BIOS with an instrumented, +modified, more recent version one, or installing brand new ACPI tables. -For a full list of ACPI tables that can be overridden, take a look at -the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in drivers/acpi/osl.c +For a full list of ACPI tables that can be upgraded/installed, take a look +at the char *table_sigs[MAX_ACPI_SIGNATURE]; definition in +drivers/acpi/tables.c. All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should be overridable, except: - ACPI_SIG_RSDP (has a signature of 6 bytes)
@@ -25,17 +27,20 @@ Both could get implemented as well. 2) What is this for ------------------- -Please keep in mind that this is a debug option. -ACPI tables should not get overridden for productive use. -If BIOS ACPI tables are overridden the kernel will get tainted with the -TAINT_OVERRIDDEN_ACPI_TABLE flag. -Complain to your platform/BIOS vendor if you find a bug which is so sever -that a workaround is not accepted in the Linux kernel. +Complain to your platform/BIOS vendor if you find a bug which is so severe +that a workaround is not accepted in the Linux kernel. And this facility +allows you to upgrade the buggy tables before your platform/BIOS vendor +releases an upgraded BIOS binary. -Still, it can and should be enabled in any kernel, because: - - There is no functional change with not instrumented initrds - - It provides a powerful feature to easily debug and test ACPI BIOS table - compatibility with the Linux kernel. +This facility can be used by platform/BIOS vendors to provide a Linux +compatible environment without modifying the underlying platform firmware. + +This facility also provides a powerful feature to easily debug and test +ACPI BIOS table compatibility with the Linux kernel by modifying old +platform provided ACPI tables or inserting new ACPI tables. + +It can and should be enabled in any kernel because there is no functional +change with not instrumented initrds. 3) How does it work
@@ -50,23 +55,31 @@ iasl -d *.dat # For example add this statement into a _PRT (PCI Routing Table) function # of the DSDT: Store("HELLO WORLD", debug) +# And increase the OEM Revision. For example, before modification: +DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000) +# After modification: +DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001) iasl -sa dsdt.dsl # Add the raw ACPI tables to an uncompressed cpio archive. -# They must be put into a /kernel/firmware/acpi directory inside the -# cpio archive. -# The uncompressed cpio archive must be the first. -# Other, typically compressed cpio archives, must be -# concatenated on top of the uncompressed one. +# They must be put into a /kernel/firmware/acpi directory inside the cpio +# archive. Note that if the table put here matches a platform table +# (similar Table Signature, and similar OEMID, and similar OEM Table ID) +# with a more recent OEM Revision, the platform table will be upgraded by +# this table. If the table put here doesn't match a platform table +# (dissimilar Table Signature, or dissimilar OEMID, or dissimilar OEM Table +# ID), this table will be appended. mkdir -p kernel/firmware/acpi cp dsdt.aml kernel/firmware/acpi -# A maximum of: #define ACPI_OVERRIDE_TABLES 10 -# tables are currently allowed (see osl.c): +# A maximum of "NR_ACPI_INITRD_TABLES (64)" tables are currently allowed +# (see osl.c): iasl -sa facp.dsl iasl -sa ssdt1.dsl cp facp.aml kernel/firmware/acpi cp ssdt1.aml kernel/firmware/acpi -# Create the uncompressed cpio archive and concatenate the original initrd -# on top: +# The uncompressed cpio archive must be the first. Other, typically +# compressed cpio archives, must be concatenated on top of the uncompressed +# one. Following command creates the uncompressed cpio archive and +# concatenates the original initrd on top: find kernel | cpio -H newc --create > /boot/instrumented_initrd cat /boot/initrd >>/boot/instrumented_initrd # reboot with increased acpi debug level, e.g. boot params:
drivers/acpi/Kconfig +4 -4
@@ -311,12 +311,12 @@ config ACPI_CUSTOM_DSDT bool default ACPI_CUSTOM_DSDT_FILE != "" -config ACPI_INITRD_TABLE_OVERRIDE - bool "ACPI tables override via initrd" +config ACPI_TABLE_UPGRADE + bool "Allow upgrading ACPI tables via initrd" depends on BLK_DEV_INITRD && X86 - default n + default y help - This option provides functionality to override arbitrary ACPI tables + This option provides functionality to upgrade arbitrary ACPI tables via initrd. No functional change if no ACPI tables are passed via initrd, therefore it's safe to say Y. See Documentation/acpi/initrd_table_override.txt for details
drivers/acpi/tables.c +34 -14
100 lines not on this page · raw message
Signature · 1 line
1.7.10
Re: [PATCH v2 3/3] ACPI / tables: Convert the initrd table override mechanisms to the table upgrade mechanism
Quoted 23 lines · Lv Zheng
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.
Quoted 4 lines
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.
I agree that we should not force lockdep disabling. I wonder if we should add a new taint (like the one I proposed in the overlay patch set) to see in bug reports that the ACPI tables have been modified.
Also, do we need a new config option? IMO it would be better if we can keep the existing config option and do the following:
* if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is set: allow arbitrary overrides (preserve the current behavior)
* if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set: allow upgrades based on the revision number
* allow adding new tables regardless of CONFIG_ACPI_INITRD_TABLE_OVERRIDE
Re: [PATCH v2 3/3] ACPI / tables: Convert the initrd table override mechanisms to the table upgrade mechanism
Quoted 36 lines · Octavian Purdila
Quoted 23 lines · Lv Zheng
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.Quoted 4 lines
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.
I agree that we should not force lockdep disabling. I wonder if we should add a new taint (like the one I proposed in the overlay patch set) to see in bug reports that the ACPI tables have been modified.
Also, do we need a new config option? IMO it would be better if we can keep the existing config option and do the following:
Quoted 7 lines
* if
CONFIG_ACPI_INITRD_TABLE_OVERRIDEis set: allow arbitrary overrides (preserve the current behavior)* if
CONFIG_ACPI_INITRD_TABLE_OVERRIDEis not set: allow upgrades based on the revision number* allow adding new tables regardless of
CONFIG_ACPI_INITRD_TABLE_OVERRIDE
Here is possible implementation for that (compile tested only):
drivers/acpi/tables.c +14 -8
@@ -435,14 +435,20 @@ static void __init check_multiple_madt(void)return ; } -static void acpi_table_taint (struct acpi_table_header *table) +static void acpi_table_taint (struct acpi_table_header *table,int taint, +const char *action) { -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 ); +enum lockdep_ok lockdep =LOCKDEP_STILL_OK ; + +pr_info (PREFIX "table %s [%4.4s-%6.6s-%8.8s]\n" , action, + table->signature, table->oem_id, table->oem_table_id); + +if (taint ==TAINT_OVERRIDDEN_ACPI_TABLE ) + lockdep =LOCKDEP_NOW_UNRELIABLE ; + +add_taint (taint, lockdep); } -#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE static u64 acpi_tables_addr;static int all_tables_size;
@@ -471,9 +477,9 @@ static const char * const table_sigs[] = {#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) -#define ACPI_OVERRIDE_TABLES 64 -static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES ]; -static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES); +#define ACPI_INITRD_TABLES 64 +static struct cpio_data __initdata acpi_initrd_files[ACPI_INITRD_TABLES ]; +static DECLARE_BITMAP(acpi_initrd_installed, ACPI_INITRD_TABLES);#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT)
@@ -488,7 +494,7 @@ static void __init acpi_table_initrd_init(void
*data, size_t size)
if (data == NULL || size == 0)
return;- for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
+ for (no = 0; no < ACPI_INITRD_TABLES; no++) {
file = find_cpio_data(cpio_path, data, size, &offset);
if (!file.data)
break;
@@ -497,7 +503,7 @@ static void __init acpi_table_initrd_init(void
*data, size_t size)
size -= offset;
if (file.size < sizeof(struct acpi_table_header)) {- pr_err("ACPI OVERRIDE: Table smaller than ACPI
header [%s%s]\n",
+ pr_err(PREFIX "initrd: Table smaller than ACPI
header [%s%s]\n",
cpio_path, file.name);
continue;
}
@@ -509,17 +515,17 @@ static void __init acpi_table_initrd_init(void
*data, size_t size)
break;
if (!table_sigs[sig]) {
- pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
+ pr_err(PREFIX "initrd: 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",
+ pr_err(PREFIX "initrd: 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",
+ pr_err(PREFIX "initrd: Bad table checksum [%s%s]\n",
cpio_path, file.name);
continue;
}
@@ -593,6 +599,8 @@ acpi_table_initrd_override(struct
acpi_table_header *existing_table,
int table_index = 0;
struct acpi_table_header *table;
u32 table_length;+ const char *action;
+ bool taint;
*length = 0;
*address = 0;
@@ -611,17 +619,29 @@ acpi_table_initrd_override(struct
acpi_table_header *existing_table,
table_length = table->length;
/* Only override tables matched */
- if (test_bit(table_index, acpi_initrd_installed) ||
- memcmp(existing_table->signature, table->signature, 4) ||
+ if (memcmp(existing_table->signature, table->signature, 4) ||
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;
}+ if (existing_table->oem_revision >= table->oem_revision) {
+ action = "override";
+ taint = TAINT_OVERRIDDEN_ACPI_TABLE;
+#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ goto next_table;
+#endif
+ } else {
+ taint = TAINT_OVERLAY_ACPI_TABLE;
+ action = "upgrade";
+ }
+
+
*length = table_length;
*address = acpi_tables_addr + table_offset;
- acpi_table_taint(existing_table);
+ acpi_table_taint(existing_table, taint, action);
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
set_bit(table_index, acpi_initrd_installed);
break;
@@ -662,7 +682,7 @@ static void __init acpi_table_initrd_scan(void)
goto next_table;
}- acpi_table_taint(table);
+ acpi_table_taint(table, TAINT_OVERLAY_ACPI_TABLE, "install");
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
acpi_install_table(acpi_tables_addr + table_offset, TRUE);
set_bit(table_index, acpi_initrd_installed);
@@ -671,25 +691,6 @@ next_table:
table_index++;
} }
-#else
-static void __init acpi_table_initrd_init(void *data, size_t size) -{
-}
-
-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)
-{
-}
-#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
acpi_status
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
@@ -714,7 +715,8 @@ acpi_os_table_override(struct acpi_table_header *existing_table,
*new_table = (struct acpi_table_header *)AmlCode;
#endif
if (*new_table != NULL)
- acpi_table_taint(existing_table);
+ acpi_table_taint(existing_table, TAINT_OVERRIDDEN_ACPI_TABLE,
+ "override");
return AE_OK;}
Quoted 12 lines · Lv Zheng
This patch introduces a table upgrade mechanism based on the existing initrd table override mechanism.
Updated due to a build error reported against
early_acpi_table_init()stub.Lv Zheng (3):
ACPI / tables: Move table override mechanisms totables.cACPI / x86: Cleanup initrd related code
ACPI / tables: Convert the initrd table override mechanisms to the
table upgrade mechanism
Quoted 8 lines
Documentation/acpi/initrd_table_override.txt | 65 +++--- arch/x86/kernel/setup.c | 12 +- drivers/acpi/Kconfig | 8 +- drivers/acpi/internal.h | 1 - drivers/acpi/osl.c | 274 ---------------------- drivers/acpi/tables.c | 312 +++++++++++++++++++++++++- include/linux/acpi.h | 10 +- 7 files changed, 365 insertions(+), 317 deletions(-)
All [1-3/3] applied, thanks!