diff options
Diffstat (limited to 'arch/x86/kernel/setup_32.c')
-rw-r--r-- | arch/x86/kernel/setup_32.c | 130 |
1 files changed, 106 insertions, 24 deletions
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 3bce4af60bb6..6802a383077d 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c | |||
@@ -188,9 +188,9 @@ extern int root_mountflags; | |||
188 | 188 | ||
189 | unsigned long saved_videomode; | 189 | unsigned long saved_videomode; |
190 | 190 | ||
191 | #define RAMDISK_IMAGE_START_MASK 0x07FF | 191 | #define RAMDISK_IMAGE_START_MASK 0x07FF |
192 | #define RAMDISK_PROMPT_FLAG 0x8000 | 192 | #define RAMDISK_PROMPT_FLAG 0x8000 |
193 | #define RAMDISK_LOAD_FLAG 0x4000 | 193 | #define RAMDISK_LOAD_FLAG 0x4000 |
194 | 194 | ||
195 | static char __initdata command_line[COMMAND_LINE_SIZE]; | 195 | static char __initdata command_line[COMMAND_LINE_SIZE]; |
196 | 196 | ||
@@ -252,7 +252,7 @@ static int __init parse_mem(char *arg) | |||
252 | * trim the existing memory map. | 252 | * trim the existing memory map. |
253 | */ | 253 | */ |
254 | unsigned long long mem_size; | 254 | unsigned long long mem_size; |
255 | 255 | ||
256 | mem_size = memparse(arg, &arg); | 256 | mem_size = memparse(arg, &arg); |
257 | limit_regions(mem_size); | 257 | limit_regions(mem_size); |
258 | user_defined_memmap = 1; | 258 | user_defined_memmap = 1; |
@@ -391,7 +391,7 @@ static void __init reserve_ebda_region(void) | |||
391 | unsigned int addr; | 391 | unsigned int addr; |
392 | addr = get_bios_ebda(); | 392 | addr = get_bios_ebda(); |
393 | if (addr) | 393 | if (addr) |
394 | reserve_bootmem(addr, PAGE_SIZE); | 394 | reserve_bootmem(addr, PAGE_SIZE); |
395 | } | 395 | } |
396 | 396 | ||
397 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 397 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
@@ -496,6 +496,100 @@ static inline void __init reserve_crashkernel(void) | |||
496 | {} | 496 | {} |
497 | #endif | 497 | #endif |
498 | 498 | ||
499 | #ifdef CONFIG_BLK_DEV_INITRD | ||
500 | |||
501 | static bool do_relocate_initrd = false; | ||
502 | |||
503 | static void __init reserve_initrd(void) | ||
504 | { | ||
505 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | ||
506 | unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; | ||
507 | unsigned long ramdisk_end = ramdisk_image + ramdisk_size; | ||
508 | unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; | ||
509 | unsigned long ramdisk_here; | ||
510 | |||
511 | initrd_start = 0; | ||
512 | |||
513 | if (!boot_params.hdr.type_of_loader || | ||
514 | !ramdisk_image || !ramdisk_size) | ||
515 | return; /* No initrd provided by bootloader */ | ||
516 | |||
517 | if (ramdisk_end < ramdisk_image) { | ||
518 | printk(KERN_ERR "initrd wraps around end of memory, " | ||
519 | "disabling initrd\n"); | ||
520 | return; | ||
521 | } | ||
522 | if (ramdisk_size >= end_of_lowmem/2) { | ||
523 | printk(KERN_ERR "initrd too large to handle, " | ||
524 | "disabling initrd\n"); | ||
525 | return; | ||
526 | } | ||
527 | if (ramdisk_end <= end_of_lowmem) { | ||
528 | /* All in lowmem, easy case */ | ||
529 | reserve_bootmem(ramdisk_image, ramdisk_size); | ||
530 | initrd_start = ramdisk_image + PAGE_OFFSET; | ||
531 | initrd_end = initrd_start+ramdisk_size; | ||
532 | return; | ||
533 | } | ||
534 | |||
535 | /* We need to move the initrd down into lowmem */ | ||
536 | ramdisk_here = (end_of_lowmem - ramdisk_size) & PAGE_MASK; | ||
537 | |||
538 | /* Note: this includes all the lowmem currently occupied by | ||
539 | the initrd, we rely on that fact to keep the data intact. */ | ||
540 | reserve_bootmem(ramdisk_here, ramdisk_size); | ||
541 | initrd_start = ramdisk_here + PAGE_OFFSET; | ||
542 | initrd_end = initrd_start + ramdisk_size; | ||
543 | |||
544 | do_relocate_initrd = true; | ||
545 | } | ||
546 | |||
547 | #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) | ||
548 | |||
549 | static void __init relocate_initrd(void) | ||
550 | { | ||
551 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | ||
552 | unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; | ||
553 | unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; | ||
554 | unsigned long ramdisk_here; | ||
555 | unsigned long slop, clen, mapaddr; | ||
556 | char *p, *q; | ||
557 | |||
558 | if (!do_relocate_initrd) | ||
559 | return; | ||
560 | |||
561 | ramdisk_here = initrd_start - PAGE_OFFSET; | ||
562 | |||
563 | q = (char *)initrd_start; | ||
564 | |||
565 | /* Copy any lowmem portion of the initrd */ | ||
566 | if (ramdisk_image < end_of_lowmem) { | ||
567 | clen = end_of_lowmem - ramdisk_image; | ||
568 | p = (char *)__va(ramdisk_image); | ||
569 | memcpy(q, p, clen); | ||
570 | q += clen; | ||
571 | ramdisk_image += clen; | ||
572 | ramdisk_size -= clen; | ||
573 | } | ||
574 | |||
575 | /* Copy the highmem portion of the initrd */ | ||
576 | while (ramdisk_size) { | ||
577 | slop = ramdisk_image & ~PAGE_MASK; | ||
578 | clen = ramdisk_size; | ||
579 | if (clen > MAX_MAP_CHUNK-slop) | ||
580 | clen = MAX_MAP_CHUNK-slop; | ||
581 | mapaddr = ramdisk_image & PAGE_MASK; | ||
582 | p = bt_ioremap(mapaddr, clen+slop); | ||
583 | memcpy(q, p+slop, clen); | ||
584 | bt_iounmap(p, clen+slop); | ||
585 | q += clen; | ||
586 | ramdisk_image += clen; | ||
587 | ramdisk_size -= clen; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
592 | |||
499 | void __init setup_bootmem_allocator(void) | 593 | void __init setup_bootmem_allocator(void) |
500 | { | 594 | { |
501 | unsigned long bootmap_size; | 595 | unsigned long bootmap_size; |
@@ -551,26 +645,10 @@ void __init setup_bootmem_allocator(void) | |||
551 | */ | 645 | */ |
552 | find_smp_config(); | 646 | find_smp_config(); |
553 | #endif | 647 | #endif |
554 | numa_kva_reserve(); | ||
555 | #ifdef CONFIG_BLK_DEV_INITRD | 648 | #ifdef CONFIG_BLK_DEV_INITRD |
556 | if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { | 649 | reserve_initrd(); |
557 | unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; | ||
558 | unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; | ||
559 | unsigned long ramdisk_end = ramdisk_image + ramdisk_size; | ||
560 | unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; | ||
561 | |||
562 | if (ramdisk_end <= end_of_lowmem) { | ||
563 | reserve_bootmem(ramdisk_image, ramdisk_size); | ||
564 | initrd_start = ramdisk_image + PAGE_OFFSET; | ||
565 | initrd_end = initrd_start+ramdisk_size; | ||
566 | } else { | ||
567 | printk(KERN_ERR "initrd extends beyond end of memory " | ||
568 | "(0x%08lx > 0x%08lx)\ndisabling initrd\n", | ||
569 | ramdisk_end, end_of_lowmem); | ||
570 | initrd_start = 0; | ||
571 | } | ||
572 | } | ||
573 | #endif | 650 | #endif |
651 | numa_kva_reserve(); | ||
574 | reserve_crashkernel(); | 652 | reserve_crashkernel(); |
575 | } | 653 | } |
576 | 654 | ||
@@ -713,15 +791,19 @@ void __init setup_arch(char **cmdline_p) | |||
713 | * NOTE: at this point the bootmem allocator is fully available. | 791 | * NOTE: at this point the bootmem allocator is fully available. |
714 | */ | 792 | */ |
715 | 793 | ||
794 | #ifdef CONFIG_BLK_DEV_INITRD | ||
795 | relocate_initrd(); | ||
796 | #endif | ||
797 | |||
716 | paravirt_post_allocator_init(); | 798 | paravirt_post_allocator_init(); |
717 | 799 | ||
718 | dmi_scan_machine(); | 800 | dmi_scan_machine(); |
719 | 801 | ||
720 | io_delay_init();; | 802 | io_delay_init(); |
721 | 803 | ||
722 | #ifdef CONFIG_X86_GENERICARCH | 804 | #ifdef CONFIG_X86_GENERICARCH |
723 | generic_apic_probe(); | 805 | generic_apic_probe(); |
724 | #endif | 806 | #endif |
725 | if (efi_enabled) | 807 | if (efi_enabled) |
726 | efi_map_memmap(); | 808 | efi_map_memmap(); |
727 | 809 | ||