* [RESEND] Early cpio decoder and ACPI table override via initrd making use of it
@ 2012-09-25 14:55 Thomas Renninger
[not found] ` <1348584961-1476-1-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:55 UTC (permalink / raw)
To: hpa-YMNOUZJC4hwAvxtiuMwx3w
Cc: lenb-DgEjT+Ai2ygdnm+yROfE0A, initramfs-u79uwXL29TY76Z2rM5mHXA,
robert.moore-ral2JQCrhuEAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, yinghai-DgEjT+Ai2ygdnm+yROfE0A
Hi,
this is the updated version with following changes as suggested
by Len and Yinghai:
- spelling corrections
- macro hiding in header files
- splitting up patches
There shouldn't be any functional changes since the last version.
I guess the only part missing is a more explicit ack from Len than
"this is not a nak"?
Then this can go into linux-next through a X86 branch pushed by
hpa (as there are quite some x86 specific parts)?
The patches are on top of latest Linus tree.
Thanks,
Thomas
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/6] lib: Add early cpio decoder
[not found] ` <1348584961-1476-1-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
@ 2012-09-25 14:55 ` Thomas Renninger
0 siblings, 0 replies; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:55 UTC (permalink / raw)
To: hpa-YMNOUZJC4hwAvxtiuMwx3w
Cc: lenb-DgEjT+Ai2ygdnm+yROfE0A, initramfs-u79uwXL29TY76Z2rM5mHXA,
robert.moore-ral2JQCrhuEAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, yinghai-DgEjT+Ai2ygdnm+yROfE0A,
H. Peter Anvin, Thomas Renninger
From: "H. Peter Anvin" <hpa-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Add a simple cpio decoder without library dependencies for the purpose
of extracting components from the initramfs blob for early kernel
uses. Intended consumers so far are microcode and ACPI override.
Signed-off-by: H. Peter Anvin <hpa-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
CC: Thomas Renninger <trenn-l3A5Bk7waGM@public.gmane.org>
Link: http://lkml.kernel.org/r/201203261651.29640.trenn-l3A5Bk7waGM@public.gmane.org
Link: https://lkml.org/lkml/2012/9/21/190
Signed-off-by: Thomas Renninger <trenn-l3A5Bk7waGM@public.gmane.org>
---
include/linux/earlycpio.h | 17 +++++
lib/Makefile | 2 +-
lib/earlycpio.c | 145 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 163 insertions(+), 1 deletions(-)
create mode 100644 include/linux/earlycpio.h
create mode 100644 lib/earlycpio.c
diff --git a/include/linux/earlycpio.h b/include/linux/earlycpio.h
new file mode 100644
index 0000000..111f46d
--- /dev/null
+++ b/include/linux/earlycpio.h
@@ -0,0 +1,17 @@
+#ifndef _LINUX_EARLYCPIO_H
+#define _LINUX_EARLYCPIO_H
+
+#include <linux/types.h>
+
+#define MAX_CPIO_FILE_NAME 18
+
+struct cpio_data {
+ void *data;
+ size_t size;
+ char name[MAX_CPIO_FILE_NAME];
+};
+
+struct cpio_data find_cpio_data(const char *path, void *data, size_t len,
+ long *offset);
+
+#endif /* _LINUX_EARLYCPIO_H */
diff --git a/lib/Makefile b/lib/Makefile
index 42d283e..0924041 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o
+ is_single_threaded.o plist.o decompress.o earlycpio.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/earlycpio.c b/lib/earlycpio.c
new file mode 100644
index 0000000..8078ef4
--- /dev/null
+++ b/lib/earlycpio.c
@@ -0,0 +1,145 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation; author H. Peter Anvin
+ *
+ * This file is part of the Linux kernel, and is made available
+ * under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * earlycpio.c
+ *
+ * Find a specific cpio member; must precede any compressed content.
+ * This is used to locate data items in the initramfs used by the
+ * kernel itself during early boot (before the main initramfs is
+ * decompressed.) It is the responsibility of the initramfs creator
+ * to ensure that these items are uncompressed at the head of the
+ * blob. Depending on the boot loader or package tool that may be a
+ * separate file or part of the same file.
+ */
+
+#include <linux/earlycpio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+enum cpio_fields {
+ C_MAGIC,
+ C_INO,
+ C_MODE,
+ C_UID,
+ C_GID,
+ C_NLINK,
+ C_MTIME,
+ C_FILESIZE,
+ C_MAJ,
+ C_MIN,
+ C_RMAJ,
+ C_RMIN,
+ C_NAMESIZE,
+ C_CHKSUM,
+ C_NFIELDS
+};
+
+/**
+ * cpio_data find_cpio_data - Search for files in an uncompressed cpio
+ * @path: The directory to search for, including a slash at the end
+ * @data: Pointer to the the cpio archive or a header inside
+ * @len: Remaining length of the cpio based on data pointer
+ * @offset: When a matching file is found, this is the offset to the
+ * beginning of the cpio. It can be used to iterate through
+ * the cpio to find all files inside of a directory path
+ *
+ * @return: struct cpio_data containing the address, length and
+ * filename (with the directory path cut off) of the found file.
+ * If you search for a filename and not for files in a directory,
+ * pass the absolute path of the filename in the cpio and make sure
+ * the match returned an empty filename string.
+ */
+
+struct cpio_data __cpuinit find_cpio_data(const char *path, void *data,
+ size_t len, long *offset)
+{
+ const size_t cpio_header_len = 8*C_NFIELDS - 2;
+ struct cpio_data cd = { NULL, 0, "" };
+ const char *p, *dptr, *nptr;
+ unsigned int ch[C_NFIELDS], *chp, v;
+ unsigned char c, x;
+ size_t mypathsize = strlen(path);
+ int i, j;
+
+ p = data;
+
+ while (len > cpio_header_len) {
+ if (!*p) {
+ /* All cpio headers need to be 4-byte aligned */
+ p += 4;
+ len -= 4;
+ continue;
+ }
+
+ j = 6; /* The magic field is only 6 characters */
+ chp = ch;
+ for (i = C_NFIELDS; i; i--) {
+ v = 0;
+ while (j--) {
+ v <<= 4;
+ c = *p++;
+
+ x = c - '0';
+ if (x < 10) {
+ v += x;
+ continue;
+ }
+
+ x = (c | 0x20) - 'a';
+ if (x < 6) {
+ v += x + 10;
+ continue;
+ }
+
+ goto quit; /* Invalid hexadecimal */
+ }
+ *chp++ = v;
+ j = 8; /* All other fields are 8 characters */
+ }
+
+ if ((ch[C_MAGIC] - 0x070701) > 1)
+ goto quit; /* Invalid magic */
+
+ len -= cpio_header_len;
+
+ dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4);
+ nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4);
+
+ if (nptr > p + len || dptr < p || nptr < dptr)
+ goto quit; /* Buffer overrun */
+
+ if ((ch[C_MODE] & 0170000) == 0100000 &&
+ ch[C_NAMESIZE] >= mypathsize &&
+ !memcmp(p, path, mypathsize)) {
+ *offset = (long)nptr - (long)data;
+ if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) {
+ pr_warn(
+ "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n",
+ p, MAX_CPIO_FILE_NAME);
+ }
+ strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME);
+
+ cd.data = (void *)dptr;
+ cd.size = ch[C_FILESIZE];
+ return cd; /* Found it! */
+ }
+ len -= (nptr - p);
+ p = nptr;
+ }
+
+quit:
+ return cd;
+}
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/6] X86 ACPI: Introduce x86 arch specific arch_reserve_mem_area() for e820 handling
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
[not found] ` <1348584961-1476-1-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
@ 2012-09-25 14:55 ` Thomas Renninger
2012-09-25 15:12 ` Thomas Renninger
2012-09-25 14:55 ` [PATCH 3/6] ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas Thomas Renninger
` (3 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:55 UTC (permalink / raw)
To: hpa
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
Thomas Renninger
This is needed for ACPI table overriding via initrd. Beside reserving
memblocks, X86 also requires to flag the memory area to E820_RESERVED or
E820_ACPI in the e820 mappings to be able to io(re)map it later.
Signed-off-by: Thomas Renninger <trenn@suse.de>
---
arch/x86/kernel/acpi/boot.c | 6 ++++++
include/linux/acpi.h | 9 +++++++++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index b2297e5..6b75777 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1700,3 +1700,9 @@ int __acpi_release_global_lock(unsigned int *lock)
} while (unlikely (val != old));
return old & 0x1;
}
+
+void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+ e820_add_region(addr, size, E820_ACPI);
+ update_e820();
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4f2a762..bf6a0ad 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -430,4 +430,13 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state,
#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
#endif
+#if CONFIG_X86
+void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
+#else
+static inline void void arch_reserve_mem_area(acpi_physical_address addr,
+ size_t size)
+{
+}
+#endif /* CONFIG_X86 */
+
#endif /*_LINUX_ACPI_H*/
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/6] ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
[not found] ` <1348584961-1476-1-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
2012-09-25 14:55 ` [PATCH 2/6] X86 ACPI: Introduce x86 arch specific arch_reserve_mem_area() for e820 handling Thomas Renninger
@ 2012-09-25 14:55 ` Thomas Renninger
[not found] ` <1348584961-1476-4-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
2012-09-25 14:55 ` [PATCH 4/6] ACPI: Implement physical address table override Thomas Renninger
` (2 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:55 UTC (permalink / raw)
To: hpa
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
Thomas Renninger
A later patch will compare them with ACPI tables that get loaded at boot or
runtime and if criteria match, a stored one is loaded.
Signed-off-by: Thomas Renninger <trenn@suse.de>
---
arch/x86/kernel/setup.c | 2 +
drivers/acpi/Kconfig | 9 ++++
drivers/acpi/osl.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 8 +++
4 files changed, 141 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f4b9b80..764e543 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -941,6 +941,8 @@ void __init setup_arch(char **cmdline_p)
reserve_initrd();
+ acpi_initrd_override((void *)initrd_start, initrd_end - initrd_start);
+
reserve_crashkernel();
vsmp_init();
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 8099895..a508f77 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -261,6 +261,15 @@ config ACPI_CUSTOM_DSDT
bool
default ACPI_CUSTOM_DSDT_FILE != ""
+config ACPI_INITRD_TABLE_OVERRIDE
+ bool
+ default y
+ help
+ This option provides functionality to override 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
+
config ACPI_BLACKLIST_YEAR
int "Disable ACPI for systems before Jan 1st this year" if X86_32
default 0
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 9eaf708..b20b079 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -534,6 +534,128 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
return AE_OK;
}
+#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
+#include <linux/earlycpio.h>
+#include <linux/memblock.h>
+
+static u64 acpi_tables_addr;
+static int all_tables_size;
+
+/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
+u8 __init acpi_table_checksum(u8 *buffer, u32 length)
+{
+ u8 sum = 0;
+ u8 *end = buffer + length;
+
+ while (buffer < end)
+ sum = (u8) (sum + *(buffer++));
+ return sum;
+}
+
+/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
+static const char * const table_sigs[] = {
+ ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
+ ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
+ ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
+ ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
+ ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
+ ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
+ ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
+ ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
+ ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
+
+/* Non-fatal errors: Affected tables/files are ignored */
+#define INVALID_TABLE(x, path, name) \
+ { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; }
+
+#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
+
+/* Must not increase 10 or needs code modification below */
+#define ACPI_OVERRIDE_TABLES 10
+
+void __init acpi_initrd_override(void *data, size_t size)
+{
+ int sig, no, table_nr = 0, total_offset = 0;
+ long offset = 0;
+ struct acpi_table_header *table;
+ char cpio_path[32] = "kernel/firmware/acpi/";
+ struct cpio_data file;
+ struct cpio_data early_initrd_files[ACPI_OVERRIDE_TABLES];
+ char *p;
+
+ if (data == NULL || size == 0)
+ return;
+
+ for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
+ file = find_cpio_data(cpio_path, data, size, &offset);
+ if (!file.data)
+ break;
+
+ data += offset;
+ size -= offset;
+
+ if (file.size < sizeof(struct acpi_table_header))
+ INVALID_TABLE("Table smaller than ACPI header",
+ cpio_path, file.name);
+
+ table = file.data;
+
+ for (sig = 0; table_sigs[sig]; sig++)
+ if (!memcmp(table->signature, table_sigs[sig], 4))
+ break;
+
+ if (!table_sigs[sig])
+ INVALID_TABLE("Unknown signature",
+ cpio_path, file.name);
+ if (file.size != table->length)
+ INVALID_TABLE("File length does not match table length",
+ cpio_path, file.name);
+ if (acpi_table_checksum(file.data, table->length))
+ INVALID_TABLE("Bad table checksum",
+ cpio_path, file.name);
+
+ pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
+ table->signature, cpio_path, file.name, table->length);
+
+ all_tables_size += table->length;
+ early_initrd_files[table_nr].data = file.data;
+ early_initrd_files[table_nr].size = file.size;
+ table_nr++;
+ }
+ if (table_nr == 0)
+ return;
+
+ acpi_tables_addr =
+ memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
+ all_tables_size, PAGE_SIZE);
+ if (!acpi_tables_addr) {
+ WARN_ON(1);
+ return;
+ }
+ /*
+ * Only calling e820_add_reserve does not work and the
+ * tables are invalid (memory got used) later.
+ * memblock_reserve works as expected and the tables won't get modified.
+ * But it's not enough on X86 because ioremap will
+ * complain later (used by acpi_os_map_memory) that the pages
+ * that should get mapped are not marked "reserved".
+ * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
+ * works fine.
+ */
+ memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size);
+ arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
+
+ p = early_ioremap(acpi_tables_addr, all_tables_size);
+
+ for (no = 0; no < table_nr; no++) {
+ memcpy(p + total_offset, early_initrd_files[no].data,
+ early_initrd_files[no].size);
+ total_offset += early_initrd_files[no].size;
+ }
+ early_iounmap(p, all_tables_size);
+}
+#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
+
acpi_status
acpi_os_table_override(struct acpi_table_header * existing_table,
struct acpi_table_header ** new_table)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index bf6a0ad..ee81cdc 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -76,6 +76,14 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
+#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
+
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
void __acpi_unmap_table(char *map, unsigned long size);
int early_acpi_boot_init(void);
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/6] ACPI: Implement physical address table override
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
` (2 preceding siblings ...)
2012-09-25 14:55 ` [PATCH 3/6] ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas Thomas Renninger
@ 2012-09-25 14:55 ` Thomas Renninger
2012-09-25 14:56 ` [PATCH 5/6] ACPI: Create acpi_table_taint() function to avoid code duplication Thomas Renninger
2012-09-25 14:56 ` [PATCH 6/6] ACPI: Document ACPI table overriding via initrd Thomas Renninger
5 siblings, 0 replies; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:55 UTC (permalink / raw)
To: hpa
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
Thomas Renninger
Previous patches stored ACPI tables provided via initrd in a memblock reserved
area.
If a table is loaded and the table type of an initrd provided one matches,
the one from initrd is prefered.
In case of a SSDT table, the OEM table id also has to match.
ACPI tables can be loaded at boot time (static table pointers in XSDT),
but also dynamically any time later via ASL commands load() or loadTable().
The override mechanism always works.
Signed-off-by: Thomas Renninger <trenn@suse.de>
---
drivers/acpi/osl.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index b20b079..007224b 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -681,12 +681,64 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
acpi_status
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
- acpi_physical_address * new_address,
- u32 *new_table_length)
+ acpi_physical_address *address,
+ u32 *table_length)
{
- return AE_SUPPORT;
-}
+#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
+ *table_length = 0;
+ *address = 0;
+ return AE_OK;
+#else
+ int table_offset = 0;
+ struct acpi_table_header *table;
+
+ *table_length = 0;
+ *address = 0;
+
+ if (!acpi_tables_addr)
+ return AE_OK;
+
+ do {
+ if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
+ WARN_ON(1);
+ return AE_OK;
+ }
+
+ table = acpi_os_map_memory(acpi_tables_addr + table_offset,
+ ACPI_HEADER_SIZE);
+
+ if (table_offset + table->length > all_tables_size) {
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ WARN_ON(1);
+ return AE_OK;
+ }
+ table_offset += table->length;
+
+ if (memcmp(existing_table->signature, table->signature, 4)) {
+ acpi_os_unmap_memory(table,
+ ACPI_HEADER_SIZE);
+ continue;
+ }
+
+ /* Only override tables with matching oem id */
+ if (memcmp(table->oem_table_id, existing_table->oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE)) {
+ acpi_os_unmap_memory(table,
+ ACPI_HEADER_SIZE);
+ continue;
+ }
+
+ table_offset -= table->length;
+ *table_length = table->length;
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ *address = acpi_tables_addr + table_offset;
+ break;
+ } while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
+
+ return AE_OK;
+#endif
+}
static irqreturn_t acpi_irq(int irq, void *dev_id)
{
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/6] ACPI: Create acpi_table_taint() function to avoid code duplication
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
` (3 preceding siblings ...)
2012-09-25 14:55 ` [PATCH 4/6] ACPI: Implement physical address table override Thomas Renninger
@ 2012-09-25 14:56 ` Thomas Renninger
2012-09-25 14:56 ` [PATCH 6/6] ACPI: Document ACPI table overriding via initrd Thomas Renninger
5 siblings, 0 replies; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:56 UTC (permalink / raw)
To: hpa
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
Thomas Renninger
There are two ways of overriding ACPI tables now, both need to taint the
the kernel.
Signed-off-by: Thomas Renninger <trenn@suse.de>
---
drivers/acpi/osl.c | 20 +++++++++++++-------
1 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 007224b..a2845ff 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -656,6 +656,15 @@ void __init acpi_initrd_override(void *data, size_t size)
}
#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
+static void acpi_table_taint(struct acpi_table_header *table)
+{
+ 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);
+}
+
+
acpi_status
acpi_os_table_override(struct acpi_table_header * existing_table,
struct acpi_table_header ** new_table)
@@ -669,13 +678,8 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
if (strncmp(existing_table->signature, "DSDT", 4) == 0)
*new_table = (struct acpi_table_header *)AmlCode;
#endif
- if (*new_table != NULL) {
- printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
- "this is unsafe: tainting kernel\n",
- existing_table->signature,
- existing_table->oem_table_id);
- add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
- }
+ if (*new_table != NULL)
+ acpi_table_taint(existing_table);
return AE_OK;
}
@@ -736,6 +740,8 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table,
break;
} while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
+ if (*address != 0)
+ acpi_table_taint(existing_table);
return AE_OK;
#endif
}
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/6] ACPI: Document ACPI table overriding via initrd
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
` (4 preceding siblings ...)
2012-09-25 14:56 ` [PATCH 5/6] ACPI: Create acpi_table_taint() function to avoid code duplication Thomas Renninger
@ 2012-09-25 14:56 ` Thomas Renninger
5 siblings, 0 replies; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 14:56 UTC (permalink / raw)
To: hpa
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
Thomas Renninger
Signed-off-by: Thomas Renninger <trenn@suse.de>
---
Documentation/acpi/initrd_table_override.txt | 94 ++++++++++++++++++++++++++
1 files changed, 94 insertions(+), 0 deletions(-)
create mode 100644 Documentation/acpi/initrd_table_override.txt
diff --git a/Documentation/acpi/initrd_table_override.txt b/Documentation/acpi/initrd_table_override.txt
new file mode 100644
index 0000000..35c3f54
--- /dev/null
+++ b/Documentation/acpi/initrd_table_override.txt
@@ -0,0 +1,94 @@
+Overriding ACPI tables via initrd
+=================================
+
+1) Introduction (What is this about)
+2) What is this for
+3) How does it work
+4) References (Where to retrieve userspace tools)
+
+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.
+
+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
+All ACPI tables iasl (Intel's ACPI compiler and disassembler) knows should
+be overridable, except:
+ - ACPI_SIG_RSDP (has a signature of 6 bytes)
+ - ACPI_SIG_FACS (does not have an ordinary ACPI table header)
+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.
+
+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.
+
+
+3) How does it work
+-------------------
+
+# Extract the machine's ACPI tables:
+cd /tmp
+acpidump >acpidump
+acpixtract -a acpidump
+# Disassemble, modify and recompile them:
+iasl -d *.dat
+# For example add this statement into a _PRT (PCI Routing Table) function
+# of the DSDT:
+Store("HELLO WORLD", debug)
+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.
+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):
+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:
+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:
+acpi.debug_level=0x2 acpi.debug_layer=0xFFFFFFFF
+# and check your syslog:
+[ 1.268089] ACPI: PCI Interrupt Routing Table [\_SB_.PCI0._PRT]
+[ 1.272091] [ACPI Debug] String [0x0B] "HELLO WORLD"
+
+iasl is able to disassemble and recompile quite a lot different,
+also static ACPI tables.
+
+
+4) Where to retrieve userspace tools
+------------------------------------
+
+iasl and acpixtract are part of Intel's ACPICA project:
+http://acpica.org/
+and should be packaged by distributions (for example in the acpica package
+on SUSE).
+
+acpidump can be found in Len Browns pmtools:
+ftp://kernel.org/pub/linux/kernel/people/lenb/acpi/utils/pmtools/acpidump
+This tool is also part of the acpica package on SUSE.
+Alternatively, used ACPI tables can be retrieved via sysfs in latest kernels:
+/sys/firmware/acpi/tables
--
1.7.6.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 2/6] X86 ACPI: Introduce x86 arch specific arch_reserve_mem_area() for e820 handling
2012-09-25 14:55 ` [PATCH 2/6] X86 ACPI: Introduce x86 arch specific arch_reserve_mem_area() for e820 handling Thomas Renninger
@ 2012-09-25 15:12 ` Thomas Renninger
2012-10-05 22:05 ` [PATCH] X86 ACPI: Use #ifdef not #if for CONFIG_X86 check Luck, Tony
0 siblings, 1 reply; 10+ messages in thread
From: Thomas Renninger @ 2012-09-25 15:12 UTC (permalink / raw)
To: hpa; +Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai
On Tuesday, September 25, 2012 04:55:57 PM Thomas Renninger wrote:
> This is needed for ACPI table overriding via initrd. Beside reserving
> memblocks, X86 also requires to flag the memory area to E820_RESERVED or
> E820_ACPI in the e820 mappings to be able to io(re)map it later.
...
> index 4f2a762..bf6a0ad 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -430,4 +430,13 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state,
> #define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
> #endif
>
> +#if CONFIG_X86
> +void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
> +#else
> +static inline void void arch_reserve_mem_area(acpi_physical_address addr,
Argh: ...void void...
I made sure every single patch compiles, so that no typo slips
in, I haven't compiled it on an other arch and there ... a typo
slipped in.
Can this get manually fixed?
Tell me and I can also resend.
Thomas
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/6] ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas
[not found] ` <1348584961-1476-4-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
@ 2012-09-25 15:15 ` H. Peter Anvin
0 siblings, 0 replies; 10+ messages in thread
From: H. Peter Anvin @ 2012-09-25 15:15 UTC (permalink / raw)
To: Thomas Renninger
Cc: lenb-DgEjT+Ai2ygdnm+yROfE0A, initramfs-u79uwXL29TY76Z2rM5mHXA,
robert.moore-ral2JQCrhuEAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, yinghai-DgEjT+Ai2ygdnm+yROfE0A
I think you got an explicit NAK for this being default y.
Thomas Renninger <trenn-l3A5Bk7waGM@public.gmane.org> wrote:
>A later patch will compare them with ACPI tables that get loaded at
>boot or
>runtime and if criteria match, a stored one is loaded.
>
>Signed-off-by: Thomas Renninger <trenn-l3A5Bk7waGM@public.gmane.org>
>---
> arch/x86/kernel/setup.c | 2 +
> drivers/acpi/Kconfig | 9 ++++
>drivers/acpi/osl.c | 122
>+++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi.h | 8 +++
> 4 files changed, 141 insertions(+), 0 deletions(-)
>
>diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
>index f4b9b80..764e543 100644
>--- a/arch/x86/kernel/setup.c
>+++ b/arch/x86/kernel/setup.c
>@@ -941,6 +941,8 @@ void __init setup_arch(char **cmdline_p)
>
> reserve_initrd();
>
>+ acpi_initrd_override((void *)initrd_start, initrd_end -
>initrd_start);
>+
> reserve_crashkernel();
>
> vsmp_init();
>diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
>index 8099895..a508f77 100644
>--- a/drivers/acpi/Kconfig
>+++ b/drivers/acpi/Kconfig
>@@ -261,6 +261,15 @@ config ACPI_CUSTOM_DSDT
> bool
> default ACPI_CUSTOM_DSDT_FILE != ""
>
>+config ACPI_INITRD_TABLE_OVERRIDE
>+ bool
>+ default y
>+ help
>+ This option provides functionality to override 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
>+
> config ACPI_BLACKLIST_YEAR
> int "Disable ACPI for systems before Jan 1st this year" if X86_32
> default 0
>diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
>index 9eaf708..b20b079 100644
>--- a/drivers/acpi/osl.c
>+++ b/drivers/acpi/osl.c
>@@ -534,6 +534,128 @@ acpi_os_predefined_override(const struct
>acpi_predefined_names *init_val,
> return AE_OK;
> }
>
>+#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
>+#include <linux/earlycpio.h>
>+#include <linux/memblock.h>
>+
>+static u64 acpi_tables_addr;
>+static int all_tables_size;
>+
>+/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
>+u8 __init acpi_table_checksum(u8 *buffer, u32 length)
>+{
>+ u8 sum = 0;
>+ u8 *end = buffer + length;
>+
>+ while (buffer < end)
>+ sum = (u8) (sum + *(buffer++));
>+ return sum;
>+}
>+
>+/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
>+static const char * const table_sigs[] = {
>+ ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
>+ ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
>+ ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
>+ ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
>+ ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
>+ ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
>+ ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
>+ ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
>+ ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
>+
>+/* Non-fatal errors: Affected tables/files are ignored */
>+#define INVALID_TABLE(x, path, name) \
>+ { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; }
>+
>+#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
>+
>+/* Must not increase 10 or needs code modification below */
>+#define ACPI_OVERRIDE_TABLES 10
>+
>+void __init acpi_initrd_override(void *data, size_t size)
>+{
>+ int sig, no, table_nr = 0, total_offset = 0;
>+ long offset = 0;
>+ struct acpi_table_header *table;
>+ char cpio_path[32] = "kernel/firmware/acpi/";
>+ struct cpio_data file;
>+ struct cpio_data early_initrd_files[ACPI_OVERRIDE_TABLES];
>+ char *p;
>+
>+ if (data == NULL || size == 0)
>+ return;
>+
>+ for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
>+ file = find_cpio_data(cpio_path, data, size, &offset);
>+ if (!file.data)
>+ break;
>+
>+ data += offset;
>+ size -= offset;
>+
>+ if (file.size < sizeof(struct acpi_table_header))
>+ INVALID_TABLE("Table smaller than ACPI header",
>+ cpio_path, file.name);
>+
>+ table = file.data;
>+
>+ for (sig = 0; table_sigs[sig]; sig++)
>+ if (!memcmp(table->signature, table_sigs[sig], 4))
>+ break;
>+
>+ if (!table_sigs[sig])
>+ INVALID_TABLE("Unknown signature",
>+ cpio_path, file.name);
>+ if (file.size != table->length)
>+ INVALID_TABLE("File length does not match table length",
>+ cpio_path, file.name);
>+ if (acpi_table_checksum(file.data, table->length))
>+ INVALID_TABLE("Bad table checksum",
>+ cpio_path, file.name);
>+
>+ pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
>+ table->signature, cpio_path, file.name, table->length);
>+
>+ all_tables_size += table->length;
>+ early_initrd_files[table_nr].data = file.data;
>+ early_initrd_files[table_nr].size = file.size;
>+ table_nr++;
>+ }
>+ if (table_nr == 0)
>+ return;
>+
>+ acpi_tables_addr =
>+ memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
>+ all_tables_size, PAGE_SIZE);
>+ if (!acpi_tables_addr) {
>+ WARN_ON(1);
>+ return;
>+ }
>+ /*
>+ * Only calling e820_add_reserve does not work and the
>+ * tables are invalid (memory got used) later.
>+ * memblock_reserve works as expected and the tables won't get
>modified.
>+ * But it's not enough on X86 because ioremap will
>+ * complain later (used by acpi_os_map_memory) that the pages
>+ * that should get mapped are not marked "reserved".
>+ * Both memblock_reserve and e820_add_region (via
>arch_reserve_mem_area)
>+ * works fine.
>+ */
>+ memblock_reserve(acpi_tables_addr, acpi_tables_addr +
>all_tables_size);
>+ arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
>+
>+ p = early_ioremap(acpi_tables_addr, all_tables_size);
>+
>+ for (no = 0; no < table_nr; no++) {
>+ memcpy(p + total_offset, early_initrd_files[no].data,
>+ early_initrd_files[no].size);
>+ total_offset += early_initrd_files[no].size;
>+ }
>+ early_iounmap(p, all_tables_size);
>+}
>+#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
>+
> acpi_status
> acpi_os_table_override(struct acpi_table_header * existing_table,
> struct acpi_table_header ** new_table)
>diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>index bf6a0ad..ee81cdc 100644
>--- a/include/linux/acpi.h
>+++ b/include/linux/acpi.h
>@@ -76,6 +76,14 @@ typedef int (*acpi_table_handler) (struct
>acpi_table_header *table);
>
>typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header
>*header, const unsigned long end);
>
>+#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
>+
> char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
> void __acpi_unmap_table(char *map, unsigned long size);
> int early_acpi_boot_init(void);
--
Sent from my mobile phone. Please excuse brevity and lack of formatting.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH] X86 ACPI: Use #ifdef not #if for CONFIG_X86 check
2012-09-25 15:12 ` Thomas Renninger
@ 2012-10-05 22:05 ` Luck, Tony
0 siblings, 0 replies; 10+ messages in thread
From: Luck, Tony @ 2012-10-05 22:05 UTC (permalink / raw)
To: Thomas Renninger
Cc: lenb, initramfs, robert.moore, linux-kernel, linux-acpi, yinghai,
hpa
Fix a build warning on ia64:
include/linux/acpi.h:437:5: warning: "CONFIG_X86" is not defined
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4f42332..f70f18d 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -434,7 +434,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
acpi_status acpi_os_prepare_sleep(u8 sleep_state,
u32 pm1a_control, u32 pm1b_control);
-#if CONFIG_X86
+#ifdef CONFIG_X86
void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
#else
static inline void arch_reserve_mem_area(acpi_physical_address addr,
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2012-10-05 22:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-25 14:55 [RESEND] Early cpio decoder and ACPI table override via initrd making use of it Thomas Renninger
[not found] ` <1348584961-1476-1-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
2012-09-25 14:55 ` [PATCH 1/6] lib: Add early cpio decoder Thomas Renninger
2012-09-25 14:55 ` [PATCH 2/6] X86 ACPI: Introduce x86 arch specific arch_reserve_mem_area() for e820 handling Thomas Renninger
2012-09-25 15:12 ` Thomas Renninger
2012-10-05 22:05 ` [PATCH] X86 ACPI: Use #ifdef not #if for CONFIG_X86 check Luck, Tony
2012-09-25 14:55 ` [PATCH 3/6] ACPI: Store valid ACPI tables passed via early initrd in reserved memblock areas Thomas Renninger
[not found] ` <1348584961-1476-4-git-send-email-trenn-l3A5Bk7waGM@public.gmane.org>
2012-09-25 15:15 ` H. Peter Anvin
2012-09-25 14:55 ` [PATCH 4/6] ACPI: Implement physical address table override Thomas Renninger
2012-09-25 14:56 ` [PATCH 5/6] ACPI: Create acpi_table_taint() function to avoid code duplication Thomas Renninger
2012-09-25 14:56 ` [PATCH 6/6] ACPI: Document ACPI table overriding via initrd Thomas Renninger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).