diff options
Diffstat (limited to 'arch/x86/kernel/setup.c')
-rw-r--r-- | arch/x86/kernel/setup.c | 224 |
1 files changed, 218 insertions, 6 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9838f2539dfc..2255782e8d4b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -223,6 +223,9 @@ unsigned long saved_video_mode; | |||
223 | #define RAMDISK_LOAD_FLAG 0x4000 | 223 | #define RAMDISK_LOAD_FLAG 0x4000 |
224 | 224 | ||
225 | static char __initdata command_line[COMMAND_LINE_SIZE]; | 225 | static char __initdata command_line[COMMAND_LINE_SIZE]; |
226 | #ifdef CONFIG_CMDLINE_BOOL | ||
227 | static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | ||
228 | #endif | ||
226 | 229 | ||
227 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) | 230 | #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) |
228 | struct edd edd; | 231 | struct edd edd; |
@@ -299,7 +302,7 @@ static void __init relocate_initrd(void) | |||
299 | if (clen > MAX_MAP_CHUNK-slop) | 302 | if (clen > MAX_MAP_CHUNK-slop) |
300 | clen = MAX_MAP_CHUNK-slop; | 303 | clen = MAX_MAP_CHUNK-slop; |
301 | mapaddr = ramdisk_image & PAGE_MASK; | 304 | mapaddr = ramdisk_image & PAGE_MASK; |
302 | p = early_ioremap(mapaddr, clen+slop); | 305 | p = early_memremap(mapaddr, clen+slop); |
303 | memcpy(q, p+slop, clen); | 306 | memcpy(q, p+slop, clen); |
304 | early_iounmap(p, clen+slop); | 307 | early_iounmap(p, clen+slop); |
305 | q += clen; | 308 | q += clen; |
@@ -376,7 +379,7 @@ static void __init parse_setup_data(void) | |||
376 | return; | 379 | return; |
377 | pa_data = boot_params.hdr.setup_data; | 380 | pa_data = boot_params.hdr.setup_data; |
378 | while (pa_data) { | 381 | while (pa_data) { |
379 | data = early_ioremap(pa_data, PAGE_SIZE); | 382 | data = early_memremap(pa_data, PAGE_SIZE); |
380 | switch (data->type) { | 383 | switch (data->type) { |
381 | case SETUP_E820_EXT: | 384 | case SETUP_E820_EXT: |
382 | parse_e820_ext(data, pa_data); | 385 | parse_e820_ext(data, pa_data); |
@@ -399,7 +402,7 @@ static void __init e820_reserve_setup_data(void) | |||
399 | return; | 402 | return; |
400 | pa_data = boot_params.hdr.setup_data; | 403 | pa_data = boot_params.hdr.setup_data; |
401 | while (pa_data) { | 404 | while (pa_data) { |
402 | data = early_ioremap(pa_data, sizeof(*data)); | 405 | data = early_memremap(pa_data, sizeof(*data)); |
403 | e820_update_range(pa_data, sizeof(*data)+data->len, | 406 | e820_update_range(pa_data, sizeof(*data)+data->len, |
404 | E820_RAM, E820_RESERVED_KERN); | 407 | E820_RAM, E820_RESERVED_KERN); |
405 | found = 1; | 408 | found = 1; |
@@ -425,7 +428,7 @@ static void __init reserve_early_setup_data(void) | |||
425 | return; | 428 | return; |
426 | pa_data = boot_params.hdr.setup_data; | 429 | pa_data = boot_params.hdr.setup_data; |
427 | while (pa_data) { | 430 | while (pa_data) { |
428 | data = early_ioremap(pa_data, sizeof(*data)); | 431 | data = early_memremap(pa_data, sizeof(*data)); |
429 | sprintf(buf, "setup data %x", data->type); | 432 | sprintf(buf, "setup data %x", data->type); |
430 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); | 433 | reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf); |
431 | pa_data = data->next; | 434 | pa_data = data->next; |
@@ -579,6 +582,190 @@ static struct x86_quirks default_x86_quirks __initdata; | |||
579 | struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; | 582 | struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; |
580 | 583 | ||
581 | /* | 584 | /* |
585 | * Some BIOSes seem to corrupt the low 64k of memory during events | ||
586 | * like suspend/resume and unplugging an HDMI cable. Reserve all | ||
587 | * remaining free memory in that area and fill it with a distinct | ||
588 | * pattern. | ||
589 | */ | ||
590 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
591 | #define MAX_SCAN_AREAS 8 | ||
592 | |||
593 | static int __read_mostly memory_corruption_check = -1; | ||
594 | |||
595 | static unsigned __read_mostly corruption_check_size = 64*1024; | ||
596 | static unsigned __read_mostly corruption_check_period = 60; /* seconds */ | ||
597 | |||
598 | static struct e820entry scan_areas[MAX_SCAN_AREAS]; | ||
599 | static int num_scan_areas; | ||
600 | |||
601 | |||
602 | static int set_corruption_check(char *arg) | ||
603 | { | ||
604 | char *end; | ||
605 | |||
606 | memory_corruption_check = simple_strtol(arg, &end, 10); | ||
607 | |||
608 | return (*end == 0) ? 0 : -EINVAL; | ||
609 | } | ||
610 | early_param("memory_corruption_check", set_corruption_check); | ||
611 | |||
612 | static int set_corruption_check_period(char *arg) | ||
613 | { | ||
614 | char *end; | ||
615 | |||
616 | corruption_check_period = simple_strtoul(arg, &end, 10); | ||
617 | |||
618 | return (*end == 0) ? 0 : -EINVAL; | ||
619 | } | ||
620 | early_param("memory_corruption_check_period", set_corruption_check_period); | ||
621 | |||
622 | static int set_corruption_check_size(char *arg) | ||
623 | { | ||
624 | char *end; | ||
625 | unsigned size; | ||
626 | |||
627 | size = memparse(arg, &end); | ||
628 | |||
629 | if (*end == '\0') | ||
630 | corruption_check_size = size; | ||
631 | |||
632 | return (size == corruption_check_size) ? 0 : -EINVAL; | ||
633 | } | ||
634 | early_param("memory_corruption_check_size", set_corruption_check_size); | ||
635 | |||
636 | |||
637 | static void __init setup_bios_corruption_check(void) | ||
638 | { | ||
639 | u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ | ||
640 | |||
641 | if (memory_corruption_check == -1) { | ||
642 | memory_corruption_check = | ||
643 | #ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK | ||
644 | 1 | ||
645 | #else | ||
646 | 0 | ||
647 | #endif | ||
648 | ; | ||
649 | } | ||
650 | |||
651 | if (corruption_check_size == 0) | ||
652 | memory_corruption_check = 0; | ||
653 | |||
654 | if (!memory_corruption_check) | ||
655 | return; | ||
656 | |||
657 | corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); | ||
658 | |||
659 | while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { | ||
660 | u64 size; | ||
661 | addr = find_e820_area_size(addr, &size, PAGE_SIZE); | ||
662 | |||
663 | if (addr == 0) | ||
664 | break; | ||
665 | |||
666 | if ((addr + size) > corruption_check_size) | ||
667 | size = corruption_check_size - addr; | ||
668 | |||
669 | if (size == 0) | ||
670 | break; | ||
671 | |||
672 | e820_update_range(addr, size, E820_RAM, E820_RESERVED); | ||
673 | scan_areas[num_scan_areas].addr = addr; | ||
674 | scan_areas[num_scan_areas].size = size; | ||
675 | num_scan_areas++; | ||
676 | |||
677 | /* Assume we've already mapped this early memory */ | ||
678 | memset(__va(addr), 0, size); | ||
679 | |||
680 | addr += size; | ||
681 | } | ||
682 | |||
683 | printk(KERN_INFO "Scanning %d areas for low memory corruption\n", | ||
684 | num_scan_areas); | ||
685 | update_e820(); | ||
686 | } | ||
687 | |||
688 | static struct timer_list periodic_check_timer; | ||
689 | |||
690 | void check_for_bios_corruption(void) | ||
691 | { | ||
692 | int i; | ||
693 | int corruption = 0; | ||
694 | |||
695 | if (!memory_corruption_check) | ||
696 | return; | ||
697 | |||
698 | for(i = 0; i < num_scan_areas; i++) { | ||
699 | unsigned long *addr = __va(scan_areas[i].addr); | ||
700 | unsigned long size = scan_areas[i].size; | ||
701 | |||
702 | for(; size; addr++, size -= sizeof(unsigned long)) { | ||
703 | if (!*addr) | ||
704 | continue; | ||
705 | printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", | ||
706 | addr, __pa(addr), *addr); | ||
707 | corruption = 1; | ||
708 | *addr = 0; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n"); | ||
713 | } | ||
714 | |||
715 | static void periodic_check_for_corruption(unsigned long data) | ||
716 | { | ||
717 | check_for_bios_corruption(); | ||
718 | mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ)); | ||
719 | } | ||
720 | |||
721 | void start_periodic_check_for_corruption(void) | ||
722 | { | ||
723 | if (!memory_corruption_check || corruption_check_period == 0) | ||
724 | return; | ||
725 | |||
726 | printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", | ||
727 | corruption_check_period); | ||
728 | |||
729 | init_timer(&periodic_check_timer); | ||
730 | periodic_check_timer.function = &periodic_check_for_corruption; | ||
731 | periodic_check_for_corruption(0); | ||
732 | } | ||
733 | #endif | ||
734 | |||
735 | static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) | ||
736 | { | ||
737 | printk(KERN_NOTICE | ||
738 | "%s detected: BIOS may corrupt low RAM, working it around.\n", | ||
739 | d->ident); | ||
740 | |||
741 | e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED); | ||
742 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | /* List of systems that have known low memory corruption BIOS problems */ | ||
748 | static struct dmi_system_id __initdata bad_bios_dmi_table[] = { | ||
749 | #ifdef CONFIG_X86_RESERVE_LOW_64K | ||
750 | { | ||
751 | .callback = dmi_low_memory_corruption, | ||
752 | .ident = "AMI BIOS", | ||
753 | .matches = { | ||
754 | DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), | ||
755 | }, | ||
756 | }, | ||
757 | { | ||
758 | .callback = dmi_low_memory_corruption, | ||
759 | .ident = "Phoenix BIOS", | ||
760 | .matches = { | ||
761 | DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), | ||
762 | }, | ||
763 | }, | ||
764 | #endif | ||
765 | {} | ||
766 | }; | ||
767 | |||
768 | /* | ||
582 | * Determine if we were loaded by an EFI loader. If so, then we have also been | 769 | * 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 | 770 | * 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 | 771 | * for initialization. Note, the efi init code path is determined by the |
@@ -665,6 +852,19 @@ void __init setup_arch(char **cmdline_p) | |||
665 | bss_resource.start = virt_to_phys(&__bss_start); | 852 | bss_resource.start = virt_to_phys(&__bss_start); |
666 | bss_resource.end = virt_to_phys(&__bss_stop)-1; | 853 | bss_resource.end = virt_to_phys(&__bss_stop)-1; |
667 | 854 | ||
855 | #ifdef CONFIG_CMDLINE_BOOL | ||
856 | #ifdef CONFIG_CMDLINE_OVERRIDE | ||
857 | strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); | ||
858 | #else | ||
859 | if (builtin_cmdline[0]) { | ||
860 | /* append boot loader cmdline to builtin */ | ||
861 | strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); | ||
862 | strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); | ||
863 | strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); | ||
864 | } | ||
865 | #endif | ||
866 | #endif | ||
867 | |||
668 | strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); | 868 | strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); |
669 | *cmdline_p = command_line; | 869 | *cmdline_p = command_line; |
670 | 870 | ||
@@ -699,6 +899,10 @@ void __init setup_arch(char **cmdline_p) | |||
699 | 899 | ||
700 | finish_e820_parsing(); | 900 | finish_e820_parsing(); |
701 | 901 | ||
902 | dmi_scan_machine(); | ||
903 | |||
904 | dmi_check_system(bad_bios_dmi_table); | ||
905 | |||
702 | #ifdef CONFIG_X86_32 | 906 | #ifdef CONFIG_X86_32 |
703 | probe_roms(); | 907 | probe_roms(); |
704 | #endif | 908 | #endif |
@@ -742,6 +946,8 @@ void __init setup_arch(char **cmdline_p) | |||
742 | #else | 946 | #else |
743 | num_physpages = max_pfn; | 947 | num_physpages = max_pfn; |
744 | 948 | ||
949 | if (cpu_has_x2apic) | ||
950 | check_x2apic(); | ||
745 | 951 | ||
746 | /* How many end-of-memory variables you have, grandma! */ | 952 | /* How many end-of-memory variables you have, grandma! */ |
747 | /* need this before calling reserve_initrd */ | 953 | /* need this before calling reserve_initrd */ |
@@ -753,6 +959,10 @@ void __init setup_arch(char **cmdline_p) | |||
753 | high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; | 959 | high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; |
754 | #endif | 960 | #endif |
755 | 961 | ||
962 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
963 | setup_bios_corruption_check(); | ||
964 | #endif | ||
965 | |||
756 | /* max_pfn_mapped is updated here */ | 966 | /* max_pfn_mapped is updated here */ |
757 | max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); | 967 | max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); |
758 | max_pfn_mapped = max_low_pfn_mapped; | 968 | max_pfn_mapped = max_low_pfn_mapped; |
@@ -781,8 +991,6 @@ void __init setup_arch(char **cmdline_p) | |||
781 | vsmp_init(); | 991 | vsmp_init(); |
782 | #endif | 992 | #endif |
783 | 993 | ||
784 | dmi_scan_machine(); | ||
785 | |||
786 | io_delay_init(); | 994 | io_delay_init(); |
787 | 995 | ||
788 | /* | 996 | /* |
@@ -790,6 +998,8 @@ void __init setup_arch(char **cmdline_p) | |||
790 | */ | 998 | */ |
791 | acpi_boot_table_init(); | 999 | acpi_boot_table_init(); |
792 | 1000 | ||
1001 | early_acpi_boot_init(); | ||
1002 | |||
793 | #ifdef CONFIG_ACPI_NUMA | 1003 | #ifdef CONFIG_ACPI_NUMA |
794 | /* | 1004 | /* |
795 | * Parse SRAT to discover nodes. | 1005 | * Parse SRAT to discover nodes. |
@@ -885,3 +1095,5 @@ void __init setup_arch(char **cmdline_p) | |||
885 | #endif | 1095 | #endif |
886 | #endif | 1096 | #endif |
887 | } | 1097 | } |
1098 | |||
1099 | |||