diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/mm/init.c | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 742d6d4ad9eb..91b522072a4d 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -474,6 +474,51 @@ static void __init memory_map_top_down(unsigned long map_start, | |||
474 | init_range_memory_mapping(real_end, map_end); | 474 | init_range_memory_mapping(real_end, map_end); |
475 | } | 475 | } |
476 | 476 | ||
477 | /** | ||
478 | * memory_map_bottom_up - Map [map_start, map_end) bottom up | ||
479 | * @map_start: start address of the target memory range | ||
480 | * @map_end: end address of the target memory range | ||
481 | * | ||
482 | * This function will setup direct mapping for memory range | ||
483 | * [map_start, map_end) in bottom-up. Since we have limited the | ||
484 | * bottom-up allocation above the kernel, the page tables will | ||
485 | * be allocated just above the kernel and we map the memory | ||
486 | * in [map_start, map_end) in bottom-up. | ||
487 | */ | ||
488 | static void __init memory_map_bottom_up(unsigned long map_start, | ||
489 | unsigned long map_end) | ||
490 | { | ||
491 | unsigned long next, new_mapped_ram_size, start; | ||
492 | unsigned long mapped_ram_size = 0; | ||
493 | /* step_size need to be small so pgt_buf from BRK could cover it */ | ||
494 | unsigned long step_size = PMD_SIZE; | ||
495 | |||
496 | start = map_start; | ||
497 | min_pfn_mapped = start >> PAGE_SHIFT; | ||
498 | |||
499 | /* | ||
500 | * We start from the bottom (@map_start) and go to the top (@map_end). | ||
501 | * The memblock_find_in_range() gets us a block of RAM from the | ||
502 | * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages | ||
503 | * for page table. | ||
504 | */ | ||
505 | while (start < map_end) { | ||
506 | if (map_end - start > step_size) { | ||
507 | next = round_up(start + 1, step_size); | ||
508 | if (next > map_end) | ||
509 | next = map_end; | ||
510 | } else | ||
511 | next = map_end; | ||
512 | |||
513 | new_mapped_ram_size = init_range_memory_mapping(start, next); | ||
514 | start = next; | ||
515 | |||
516 | if (new_mapped_ram_size > mapped_ram_size) | ||
517 | step_size = get_new_step_size(step_size); | ||
518 | mapped_ram_size += new_mapped_ram_size; | ||
519 | } | ||
520 | } | ||
521 | |||
477 | void __init init_mem_mapping(void) | 522 | void __init init_mem_mapping(void) |
478 | { | 523 | { |
479 | unsigned long end; | 524 | unsigned long end; |
@@ -489,8 +534,25 @@ void __init init_mem_mapping(void) | |||
489 | /* the ISA range is always mapped regardless of memory holes */ | 534 | /* the ISA range is always mapped regardless of memory holes */ |
490 | init_memory_mapping(0, ISA_END_ADDRESS); | 535 | init_memory_mapping(0, ISA_END_ADDRESS); |
491 | 536 | ||
492 | /* setup direct mapping for range [ISA_END_ADDRESS, end) in top-down*/ | 537 | /* |
493 | memory_map_top_down(ISA_END_ADDRESS, end); | 538 | * If the allocation is in bottom-up direction, we setup direct mapping |
539 | * in bottom-up, otherwise we setup direct mapping in top-down. | ||
540 | */ | ||
541 | if (memblock_bottom_up()) { | ||
542 | unsigned long kernel_end = __pa_symbol(_end); | ||
543 | |||
544 | /* | ||
545 | * we need two separate calls here. This is because we want to | ||
546 | * allocate page tables above the kernel. So we first map | ||
547 | * [kernel_end, end) to make memory above the kernel be mapped | ||
548 | * as soon as possible. And then use page tables allocated above | ||
549 | * the kernel to map [ISA_END_ADDRESS, kernel_end). | ||
550 | */ | ||
551 | memory_map_bottom_up(kernel_end, end); | ||
552 | memory_map_bottom_up(ISA_END_ADDRESS, kernel_end); | ||
553 | } else { | ||
554 | memory_map_top_down(ISA_END_ADDRESS, end); | ||
555 | } | ||
494 | 556 | ||
495 | #ifdef CONFIG_X86_64 | 557 | #ifdef CONFIG_X86_64 |
496 | if (max_pfn > max_low_pfn) { | 558 | if (max_pfn > max_low_pfn) { |