diff options
Diffstat (limited to 'arch/x86/kernel/setup.c')
-rw-r--r-- | arch/x86/kernel/setup.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 362d4e7f2d38..ee89ebc5aabc 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -579,6 +579,89 @@ static struct x86_quirks default_x86_quirks __initdata; | |||
579 | struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; | 579 | struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; |
580 | 580 | ||
581 | /* | 581 | /* |
582 | * Some BIOSes seem to corrupt the low 64k of memory during events | ||
583 | * like suspend/resume and unplugging an HDMI cable. Reserve all | ||
584 | * remaining free memory in that area and fill it with a distinct | ||
585 | * pattern. | ||
586 | */ | ||
587 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
588 | #define MAX_SCAN_AREAS 8 | ||
589 | static struct e820entry scan_areas[MAX_SCAN_AREAS]; | ||
590 | static int num_scan_areas; | ||
591 | |||
592 | static void __init setup_bios_corruption_check(void) | ||
593 | { | ||
594 | u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ | ||
595 | |||
596 | while(addr < 0x10000 && num_scan_areas < MAX_SCAN_AREAS) { | ||
597 | u64 size; | ||
598 | addr = find_e820_area_size(addr, &size, PAGE_SIZE); | ||
599 | |||
600 | if (addr == 0) | ||
601 | break; | ||
602 | |||
603 | if ((addr + size) > 0x10000) | ||
604 | size = 0x10000 - addr; | ||
605 | |||
606 | if (size == 0) | ||
607 | break; | ||
608 | |||
609 | e820_update_range(addr, size, E820_RAM, E820_RESERVED); | ||
610 | scan_areas[num_scan_areas].addr = addr; | ||
611 | scan_areas[num_scan_areas].size = size; | ||
612 | num_scan_areas++; | ||
613 | |||
614 | /* Assume we've already mapped this early memory */ | ||
615 | memset(__va(addr), 0, size); | ||
616 | |||
617 | addr += size; | ||
618 | } | ||
619 | |||
620 | printk(KERN_INFO "scanning %d areas for BIOS corruption\n", | ||
621 | num_scan_areas); | ||
622 | update_e820(); | ||
623 | } | ||
624 | |||
625 | static int __read_mostly bios_corruption_check = 1; | ||
626 | |||
627 | void check_for_bios_corruption(void) | ||
628 | { | ||
629 | int i; | ||
630 | int corruption = 0; | ||
631 | |||
632 | if (!bios_corruption_check) | ||
633 | return; | ||
634 | |||
635 | for(i = 0; i < num_scan_areas; i++) { | ||
636 | unsigned long *addr = __va(scan_areas[i].addr); | ||
637 | unsigned long size = scan_areas[i].size; | ||
638 | |||
639 | for(; size; addr++, size -= sizeof(unsigned long)) { | ||
640 | if (!*addr) | ||
641 | continue; | ||
642 | printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", | ||
643 | addr, __pa(addr), *addr); | ||
644 | corruption = 1; | ||
645 | *addr = 0; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | if (corruption) | ||
650 | dump_stack(); | ||
651 | } | ||
652 | |||
653 | static int set_bios_corruption_check(char *arg) | ||
654 | { | ||
655 | char *end; | ||
656 | |||
657 | bios_corruption_check = simple_strtol(arg, &end, 10); | ||
658 | |||
659 | return (*end == 0) ? 0 : -EINVAL; | ||
660 | } | ||
661 | early_param("bios_corruption_check", set_bios_corruption_check); | ||
662 | #endif | ||
663 | |||
664 | /* | ||
582 | * Determine if we were loaded by an EFI loader. If so, then we have also been | 665 | * Determine if we were loaded by an EFI loader. If so, then we have also been |
583 | * passed the efi memmap, systab, etc., so we should use these data structures | 666 | * passed the efi memmap, systab, etc., so we should use these data structures |
584 | * for initialization. Note, the efi init code path is determined by the | 667 | * for initialization. Note, the efi init code path is determined by the |
@@ -750,6 +833,10 @@ void __init setup_arch(char **cmdline_p) | |||
750 | high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; | 833 | high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; |
751 | #endif | 834 | #endif |
752 | 835 | ||
836 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
837 | setup_bios_corruption_check(); | ||
838 | #endif | ||
839 | |||
753 | /* max_pfn_mapped is updated here */ | 840 | /* max_pfn_mapped is updated here */ |
754 | max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); | 841 | max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); |
755 | max_pfn_mapped = max_low_pfn_mapped; | 842 | max_pfn_mapped = max_low_pfn_mapped; |