aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c224
1 files changed, 205 insertions, 19 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 9eaf708f5885..3ff267861541 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -534,6 +534,137 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
534 return AE_OK; 534 return AE_OK;
535} 535}
536 536
537#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
538#include <linux/earlycpio.h>
539#include <linux/memblock.h>
540
541static u64 acpi_tables_addr;
542static int all_tables_size;
543
544/* Copied from acpica/tbutils.c:acpi_tb_checksum() */
545u8 __init acpi_table_checksum(u8 *buffer, u32 length)
546{
547 u8 sum = 0;
548 u8 *end = buffer + length;
549
550 while (buffer < end)
551 sum = (u8) (sum + *(buffer++));
552 return sum;
553}
554
555/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
556static const char * const table_sigs[] = {
557 ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
558 ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
559 ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
560 ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
561 ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
562 ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
563 ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
564 ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
565 ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
566
567/* Non-fatal errors: Affected tables/files are ignored */
568#define INVALID_TABLE(x, path, name) \
569 { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; }
570
571#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
572
573/* Must not increase 10 or needs code modification below */
574#define ACPI_OVERRIDE_TABLES 10
575
576void __init acpi_initrd_override(void *data, size_t size)
577{
578 int sig, no, table_nr = 0, total_offset = 0;
579 long offset = 0;
580 struct acpi_table_header *table;
581 char cpio_path[32] = "kernel/firmware/acpi/";
582 struct cpio_data file;
583 struct cpio_data early_initrd_files[ACPI_OVERRIDE_TABLES];
584 char *p;
585
586 if (data == NULL || size == 0)
587 return;
588
589 for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) {
590 file = find_cpio_data(cpio_path, data, size, &offset);
591 if (!file.data)
592 break;
593
594 data += offset;
595 size -= offset;
596
597 if (file.size < sizeof(struct acpi_table_header))
598 INVALID_TABLE("Table smaller than ACPI header",
599 cpio_path, file.name);
600
601 table = file.data;
602
603 for (sig = 0; table_sigs[sig]; sig++)
604 if (!memcmp(table->signature, table_sigs[sig], 4))
605 break;
606
607 if (!table_sigs[sig])
608 INVALID_TABLE("Unknown signature",
609 cpio_path, file.name);
610 if (file.size != table->length)
611 INVALID_TABLE("File length does not match table length",
612 cpio_path, file.name);
613 if (acpi_table_checksum(file.data, table->length))
614 INVALID_TABLE("Bad table checksum",
615 cpio_path, file.name);
616
617 pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
618 table->signature, cpio_path, file.name, table->length);
619
620 all_tables_size += table->length;
621 early_initrd_files[table_nr].data = file.data;
622 early_initrd_files[table_nr].size = file.size;
623 table_nr++;
624 }
625 if (table_nr == 0)
626 return;
627
628 acpi_tables_addr =
629 memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
630 all_tables_size, PAGE_SIZE);
631 if (!acpi_tables_addr) {
632 WARN_ON(1);
633 return;
634 }
635 /*
636 * Only calling e820_add_reserve does not work and the
637 * tables are invalid (memory got used) later.
638 * memblock_reserve works as expected and the tables won't get modified.
639 * But it's not enough on X86 because ioremap will
640 * complain later (used by acpi_os_map_memory) that the pages
641 * that should get mapped are not marked "reserved".
642 * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
643 * works fine.
644 */
645 memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size);
646 arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
647
648 p = early_ioremap(acpi_tables_addr, all_tables_size);
649
650 for (no = 0; no < table_nr; no++) {
651 memcpy(p + total_offset, early_initrd_files[no].data,
652 early_initrd_files[no].size);
653 total_offset += early_initrd_files[no].size;
654 }
655 early_iounmap(p, all_tables_size);
656}
657#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */
658
659static void acpi_table_taint(struct acpi_table_header *table)
660{
661 pr_warn(PREFIX
662 "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
663 table->signature, table->oem_table_id);
664 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
665}
666
667
537acpi_status 668acpi_status
538acpi_os_table_override(struct acpi_table_header * existing_table, 669acpi_os_table_override(struct acpi_table_header * existing_table,
539 struct acpi_table_header ** new_table) 670 struct acpi_table_header ** new_table)
@@ -547,24 +678,73 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
547 if (strncmp(existing_table->signature, "DSDT", 4) == 0) 678 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
548 *new_table = (struct acpi_table_header *)AmlCode; 679 *new_table = (struct acpi_table_header *)AmlCode;
549#endif 680#endif
550 if (*new_table != NULL) { 681 if (*new_table != NULL)
551 printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " 682 acpi_table_taint(existing_table);
552 "this is unsafe: tainting kernel\n",
553 existing_table->signature,
554 existing_table->oem_table_id);
555 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
556 }
557 return AE_OK; 683 return AE_OK;
558} 684}
559 685
560acpi_status 686acpi_status
561acpi_os_physical_table_override(struct acpi_table_header *existing_table, 687acpi_os_physical_table_override(struct acpi_table_header *existing_table,
562 acpi_physical_address * new_address, 688 acpi_physical_address *address,
563 u32 *new_table_length) 689 u32 *table_length)
564{ 690{
565 return AE_SUPPORT; 691#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
566} 692 *table_length = 0;
693 *address = 0;
694 return AE_OK;
695#else
696 int table_offset = 0;
697 struct acpi_table_header *table;
698
699 *table_length = 0;
700 *address = 0;
701
702 if (!acpi_tables_addr)
703 return AE_OK;
704
705 do {
706 if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
707 WARN_ON(1);
708 return AE_OK;
709 }
710
711 table = acpi_os_map_memory(acpi_tables_addr + table_offset,
712 ACPI_HEADER_SIZE);
713
714 if (table_offset + table->length > all_tables_size) {
715 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
716 WARN_ON(1);
717 return AE_OK;
718 }
567 719
720 table_offset += table->length;
721
722 if (memcmp(existing_table->signature, table->signature, 4)) {
723 acpi_os_unmap_memory(table,
724 ACPI_HEADER_SIZE);
725 continue;
726 }
727
728 /* Only override tables with matching oem id */
729 if (memcmp(table->oem_table_id, existing_table->oem_table_id,
730 ACPI_OEM_TABLE_ID_SIZE)) {
731 acpi_os_unmap_memory(table,
732 ACPI_HEADER_SIZE);
733 continue;
734 }
735
736 table_offset -= table->length;
737 *table_length = table->length;
738 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
739 *address = acpi_tables_addr + table_offset;
740 break;
741 } while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
742
743 if (*address != 0)
744 acpi_table_taint(existing_table);
745 return AE_OK;
746#endif
747}
568 748
569static irqreturn_t acpi_irq(int irq, void *dev_id) 749static irqreturn_t acpi_irq(int irq, void *dev_id)
570{ 750{
@@ -932,7 +1112,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
932 * having a static work_struct. 1112 * having a static work_struct.
933 */ 1113 */
934 1114
935 dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); 1115 dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
936 if (!dpc) 1116 if (!dpc)
937 return AE_NO_MEMORY; 1117 return AE_NO_MEMORY;
938 1118
@@ -944,17 +1124,22 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
944 * because the hotplug code may call driver .remove() functions, 1124 * because the hotplug code may call driver .remove() functions,
945 * which invoke flush_scheduled_work/acpi_os_wait_events_complete 1125 * which invoke flush_scheduled_work/acpi_os_wait_events_complete
946 * to flush these workqueues. 1126 * to flush these workqueues.
1127 *
1128 * To prevent lockdep from complaining unnecessarily, make sure that
1129 * there is a different static lockdep key for each workqueue by using
1130 * INIT_WORK() for each of them separately.
947 */ 1131 */
948 queue = hp ? kacpi_hotplug_wq : 1132 if (hp) {
949 (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); 1133 queue = kacpi_hotplug_wq;
950 dpc->wait = hp ? 1 : 0; 1134 dpc->wait = 1;
951
952 if (queue == kacpi_hotplug_wq)
953 INIT_WORK(&dpc->work, acpi_os_execute_deferred); 1135 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
954 else if (queue == kacpi_notify_wq) 1136 } else if (type == OSL_NOTIFY_HANDLER) {
1137 queue = kacpi_notify_wq;
955 INIT_WORK(&dpc->work, acpi_os_execute_deferred); 1138 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
956 else 1139 } else {
1140 queue = kacpid_wq;
957 INIT_WORK(&dpc->work, acpi_os_execute_deferred); 1141 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
1142 }
958 1143
959 /* 1144 /*
960 * On some machines, a software-initiated SMI causes corruption unless 1145 * On some machines, a software-initiated SMI causes corruption unless
@@ -986,6 +1171,7 @@ acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
986{ 1171{
987 return __acpi_os_execute(0, function, context, 1); 1172 return __acpi_os_execute(0, function, context, 1);
988} 1173}
1174EXPORT_SYMBOL(acpi_os_hotplug_execute);
989 1175
990void acpi_os_wait_events_complete(void) 1176void acpi_os_wait_events_complete(void)
991{ 1177{