Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 344048
b: refs/heads/master
c: 53aac44
h: refs/heads/master
v: v3
  • Loading branch information
Thomas Renninger authored and H. Peter Anvin committed Oct 1, 2012
1 parent b6e4bfe commit f9bd18f
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8e30524dcc0d0ac1a18a5cee482b9d9cde3cb332
refs/heads/master: 53aac44c904abbad9f474f652f099de13b5c3563
2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions trunk/drivers/acpi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ config ACPI_CUSTOM_DSDT
bool
default ACPI_CUSTOM_DSDT_FILE != ""

config ACPI_INITRD_TABLE_OVERRIDE
bool "ACPI tables can be passed via uncompressed cpio in initrd"
default n
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
Expand Down
122 changes: 122 additions & 0 deletions trunk/drivers/acpi/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f9bd18f

Please sign in to comment.