diff mbox

[RFC,v2,02/10] acpi: decouple initrd table install from CONFIG_ACPI_INITRD_TABLE_OVERRIDE

Message ID 1461105548-20618-3-git-send-email-octavian.purdila@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Octavian Purdila April 19, 2016, 10:39 p.m. UTC
The ACPI override and overlay functionality is different, with the
latter being more then a debug option. Allow loading of ACPI tables from
initrd even if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not selected.

The patch also switches to using TAINT_OVERLAY_ACPI_TABLE and adds
documentation about how to load SSDT tables from initrd.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/acpi/ssdt-overlays.txt | 26 ++++++++++++
 arch/x86/kernel/setup.c              |  2 +-
 drivers/acpi/osl.c                   | 80 +++++++++++++++++++-----------------
 include/linux/acpi.h                 |  8 +---
 4 files changed, 71 insertions(+), 45 deletions(-)
diff mbox

Patch

diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt
index 54ee74a..c328f6a 100644
--- a/Documentation/acpi/ssdt-overlays.txt
+++ b/Documentation/acpi/ssdt-overlays.txt
@@ -62,3 +62,29 @@  AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes
 
 The resulting AML code can then be loaded by the kernel using one of the methods
 below.
+
+== Loading ACPI SSDTs from initrd ==
+
+This option allows loading of user defined SSDTs from initrd and it is useful
+when the system does not support EFI or when there is not enough EFI storage.
+
+It works in a similar way with initrd based ACPI tables overrides: SSDT aml code
+must be placed in the first, uncompressed, initrd under the
+"kernel/firmware/acpi" path. Multiple files can be used and this will translate
+in loading multiple tables. Only SSDT and OEM tables are allowed.
+
+Here is an example:
+
+# 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.
+mkdir -p kernel/firmware/acpi
+cp ssdt.aml kernel/firmware/acpi
+
+# Create the uncompressed cpio archive and concatenate the original initrd
+# on top:
+find kernel | cpio -H newc --create > /boot/instrumented_initrd
+cat /boot/initrd >>/boot/instrumented_initrd
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 2367ae0..1908668 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -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);
+	acpi_table_initrd_init((void *)initrd_start, initrd_end - initrd_start);
 #endif
 
 	vsmp_init();
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 814d5f8..dcc99b4 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -602,15 +602,24 @@  acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
 	return AE_OK;
 }
 
-static void acpi_table_taint(struct acpi_table_header *table)
+static void acpi_table_taint(struct acpi_table_header *table, bool override)
 {
-	pr_warn(PREFIX
-		"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_ok;
+	unsigned int taint;
+
+	if (override) {
+		pr_warn(PREFIX "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
+			table->signature, table->oem_table_id);
+		lockdep_ok = false;
+		taint = TAINT_OVERRIDDEN_ACPI_TABLE;
+	} else {
+		lockdep_ok = true;
+		taint = TAINT_OVERLAY_ACPI_TABLE;
+	}
+
+	add_taint(taint, lockdep_ok);
 }
 
-#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
 #include <linux/earlycpio.h>
 #include <linux/memblock.h>
 
@@ -642,13 +651,13 @@  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 acpi_initrd_files[ACPI_INITRD_TABLES] __initdata;
+static DECLARE_BITMAP(acpi_initrd_installed, ACPI_INITRD_TABLES);
 
 #define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
 
-void __init acpi_initrd_override(void *data, size_t size)
+void __init acpi_table_initrd_init(void *data, size_t size)
 {
 	int sig, no, table_nr = 0, total_offset = 0;
 	long offset = 0;
@@ -659,7 +668,7 @@  void __init acpi_initrd_override(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;
@@ -668,8 +677,8 @@  void __init acpi_initrd_override(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",
-				cpio_path, file.name);
+			pr_err(PREFIX "initrd: Table smaller than ACPI header [%s%s]\n",
+			       cpio_path, file.name);
 			continue;
 		}
 
@@ -680,18 +689,18 @@  void __init acpi_initrd_override(void *data, size_t size)
 				break;
 
 		if (!table_sigs[sig]) {
-			pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
-				cpio_path, file.name);
+			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",
-				cpio_path, file.name);
+			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",
-				cpio_path, file.name);
+			pr_err(PREFIX "initrd: Bad table checksum [%s%s]\n",
+			       cpio_path, file.name);
 			continue;
 		}
 
@@ -756,6 +765,7 @@  void __init acpi_initrd_override(void *data, size_t size)
 	}
 }
 
+#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
 acpi_status
 acpi_os_physical_table_override(struct acpi_table_header *existing_table,
 				acpi_physical_address *address, u32 *length)
@@ -792,7 +802,7 @@  acpi_os_physical_table_override(struct acpi_table_header *existing_table,
 
 		*length = table_length;
 		*address = acpi_tables_addr + table_offset;
-		acpi_table_taint(existing_table);
+		acpi_table_taint(existing_table, true);
 		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
 		set_bit(table_index, acpi_initrd_installed);
 		break;
@@ -803,6 +813,17 @@  next_table:
 	}
 	return AE_OK;
 }
+#else
+acpi_status
+acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+				acpi_physical_address *address,
+				u32 *table_length)
+{
+	*table_length = 0;
+	*address = 0;
+	return AE_OK;
+}
+#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
 
 void __init acpi_initrd_initialize_tables(void)
 {
@@ -833,7 +854,7 @@  void __init acpi_initrd_initialize_tables(void)
 			goto next_table;
 		}
 
-		acpi_table_taint(table);
+		acpi_table_taint(table, false);
 		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
 		acpi_install_table(acpi_tables_addr + table_offset, TRUE);
 		set_bit(table_index, acpi_initrd_installed);
@@ -842,21 +863,6 @@  next_table:
 		table_index++;
 	}
 }
-#else
-acpi_status
-acpi_os_physical_table_override(struct acpi_table_header *existing_table,
-				acpi_physical_address *address,
-				u32 *table_length)
-{
-	*table_length = 0;
-	*address = 0;
-	return AE_OK;
-}
-
-void __init acpi_initrd_initialize_tables(void)
-{
-}
-#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
 
 acpi_status
 acpi_os_table_override(struct acpi_table_header *existing_table,
@@ -872,7 +878,7 @@  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, true);
 	return AE_OK;
 }
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 06ed7e5..d4a3cb2 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -190,13 +190,7 @@  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
+void acpi_table_initrd_init(void *data, size_t size);
 
 #define BAD_MADT_ENTRY(entry, end) (					    \
 		(!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \