aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/init.c')
-rw-r--r--arch/x86/mm/init.c148
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 */ 402static unsigned long __init get_new_step_size(unsigned long step_size)
403#define STEP_SIZE_SHIFT 5 403{
404void __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 */
431static 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 */
488static 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
522void __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) {