diff options
Diffstat (limited to 'arch/x86/mm/init.c')
-rw-r--r-- | arch/x86/mm/init.c | 148 |
1 files changed, 123 insertions, 25 deletions
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 04664cdb7fda..f97130618113 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -53,12 +53,12 @@ __ref void *alloc_low_pages(unsigned int num) | |||
53 | if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) { | 53 | if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) { |
54 | unsigned long ret; | 54 | unsigned long ret; |
55 | if (min_pfn_mapped >= max_pfn_mapped) | 55 | if (min_pfn_mapped >= max_pfn_mapped) |
56 | panic("alloc_low_page: ran out of memory"); | 56 | panic("alloc_low_pages: ran out of memory"); |
57 | ret = memblock_find_in_range(min_pfn_mapped << PAGE_SHIFT, | 57 | ret = memblock_find_in_range(min_pfn_mapped << PAGE_SHIFT, |
58 | max_pfn_mapped << PAGE_SHIFT, | 58 | max_pfn_mapped << PAGE_SHIFT, |
59 | PAGE_SIZE * num , PAGE_SIZE); | 59 | PAGE_SIZE * num , PAGE_SIZE); |
60 | if (!ret) | 60 | if (!ret) |
61 | panic("alloc_low_page: can not alloc memory"); | 61 | panic("alloc_low_pages: can not alloc memory"); |
62 | memblock_reserve(ret, PAGE_SIZE * num); | 62 | memblock_reserve(ret, PAGE_SIZE * num); |
63 | pfn = ret >> PAGE_SHIFT; | 63 | pfn = ret >> PAGE_SHIFT; |
64 | } else { | 64 | } else { |
@@ -399,29 +399,46 @@ static unsigned long __init init_range_memory_mapping( | |||
399 | return mapped_ram_size; | 399 | return mapped_ram_size; |
400 | } | 400 | } |
401 | 401 | ||
402 | /* (PUD_SHIFT-PMD_SHIFT)/2 */ | 402 | static unsigned long __init get_new_step_size(unsigned long step_size) |
403 | #define STEP_SIZE_SHIFT 5 | 403 | { |
404 | void __init init_mem_mapping(void) | 404 | /* |
405 | * Explain why we shift by 5 and why we don't have to worry about | ||
406 | * 'step_size << 5' overflowing: | ||
407 | * | ||
408 | * initial mapped size is PMD_SIZE (2M). | ||
409 | * We can not set step_size to be PUD_SIZE (1G) yet. | ||
410 | * In worse case, when we cross the 1G boundary, and | ||
411 | * PG_LEVEL_2M is not set, we will need 1+1+512 pages (2M + 8k) | ||
412 | * to map 1G range with PTE. Use 5 as shift for now. | ||
413 | * | ||
414 | * Don't need to worry about overflow, on 32bit, when step_size | ||
415 | * is 0, round_down() returns 0 for start, and that turns it | ||
416 | * into 0x100000000ULL. | ||
417 | */ | ||
418 | return step_size << 5; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * memory_map_top_down - Map [map_start, map_end) top down | ||
423 | * @map_start: start address of the target memory range | ||
424 | * @map_end: end address of the target memory range | ||
425 | * | ||
426 | * This function will setup direct mapping for memory range | ||
427 | * [map_start, map_end) in top-down. That said, the page tables | ||
428 | * will be allocated at the end of the memory, and we map the | ||
429 | * memory in top-down. | ||
430 | */ | ||
431 | static void __init memory_map_top_down(unsigned long map_start, | ||
432 | unsigned long map_end) | ||
405 | { | 433 | { |
406 | unsigned long end, real_end, start, last_start; | 434 | unsigned long real_end, start, last_start; |
407 | unsigned long step_size; | 435 | unsigned long step_size; |
408 | unsigned long addr; | 436 | unsigned long addr; |
409 | unsigned long mapped_ram_size = 0; | 437 | unsigned long mapped_ram_size = 0; |
410 | unsigned long new_mapped_ram_size; | 438 | unsigned long new_mapped_ram_size; |
411 | 439 | ||
412 | probe_page_size_mask(); | ||
413 | |||
414 | #ifdef CONFIG_X86_64 | ||
415 | end = max_pfn << PAGE_SHIFT; | ||
416 | #else | ||
417 | end = max_low_pfn << PAGE_SHIFT; | ||
418 | #endif | ||
419 | |||
420 | /* the ISA range is always mapped regardless of memory holes */ | ||
421 | init_memory_mapping(0, ISA_END_ADDRESS); | ||
422 | |||
423 | /* xen has big range in reserved near end of ram, skip it at first.*/ | 440 | /* xen has big range in reserved near end of ram, skip it at first.*/ |
424 | addr = memblock_find_in_range(ISA_END_ADDRESS, end, PMD_SIZE, PMD_SIZE); | 441 | addr = memblock_find_in_range(map_start, map_end, PMD_SIZE, PMD_SIZE); |
425 | real_end = addr + PMD_SIZE; | 442 | real_end = addr + PMD_SIZE; |
426 | 443 | ||
427 | /* step_size need to be small so pgt_buf from BRK could cover it */ | 444 | /* step_size need to be small so pgt_buf from BRK could cover it */ |
@@ -436,25 +453,106 @@ void __init init_mem_mapping(void) | |||
436 | * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages | 453 | * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages |
437 | * for page table. | 454 | * for page table. |
438 | */ | 455 | */ |
439 | while (last_start > ISA_END_ADDRESS) { | 456 | while (last_start > map_start) { |
440 | if (last_start > step_size) { | 457 | if (last_start > step_size) { |
441 | start = round_down(last_start - 1, step_size); | 458 | start = round_down(last_start - 1, step_size); |
442 | if (start < ISA_END_ADDRESS) | 459 | if (start < map_start) |
443 | start = ISA_END_ADDRESS; | 460 | start = map_start; |
444 | } else | 461 | } else |
445 | start = ISA_END_ADDRESS; | 462 | start = map_start; |
446 | new_mapped_ram_size = init_range_memory_mapping(start, | 463 | new_mapped_ram_size = init_range_memory_mapping(start, |
447 | last_start); | 464 | last_start); |
448 | last_start = start; | 465 | last_start = start; |
449 | min_pfn_mapped = last_start >> PAGE_SHIFT; | 466 | min_pfn_mapped = last_start >> PAGE_SHIFT; |
450 | /* only increase step_size after big range get mapped */ | 467 | /* only increase step_size after big range get mapped */ |
451 | if (new_mapped_ram_size > mapped_ram_size) | 468 | if (new_mapped_ram_size > mapped_ram_size) |
452 | step_size <<= STEP_SIZE_SHIFT; | 469 | step_size = get_new_step_size(step_size); |
453 | mapped_ram_size += new_mapped_ram_size; | 470 | mapped_ram_size += new_mapped_ram_size; |
454 | } | 471 | } |
455 | 472 | ||
456 | if (real_end < end) | 473 | if (real_end < map_end) |
457 | init_range_memory_mapping(real_end, end); | 474 | init_range_memory_mapping(real_end, map_end); |
475 | } | ||
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 | |||
522 | void __init init_mem_mapping(void) | ||
523 | { | ||
524 | unsigned long end; | ||
525 | |||
526 | probe_page_size_mask(); | ||
527 | |||
528 | #ifdef CONFIG_X86_64 | ||
529 | end = max_pfn << PAGE_SHIFT; | ||
530 | #else | ||
531 | end = max_low_pfn << PAGE_SHIFT; | ||
532 | #endif | ||
533 | |||
534 | /* the ISA range is always mapped regardless of memory holes */ | ||
535 | init_memory_mapping(0, ISA_END_ADDRESS); | ||
536 | |||
537 | /* | ||
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 | } | ||
458 | 556 | ||
459 | #ifdef CONFIG_X86_64 | 557 | #ifdef CONFIG_X86_64 |
460 | if (max_pfn > max_low_pfn) { | 558 | if (max_pfn > max_low_pfn) { |