x86: introduce init_memory_mapping for 32bit #1
... so can we use mem below max_low_pfn earlier. this allows us to move several functions more early instead of waiting to after paging_init. That includes moving relocate_initrd() earlier in the bootup, and kva related early setup done in initmem_init. (in followup patches) Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
c3c2fee384
commit
4e29684c40
3 changed files with 120 additions and 33 deletions
|
@ -226,10 +226,8 @@ static void __init reserve_initrd(void)
|
|||
}
|
||||
|
||||
/* We need to move the initrd down into lowmem */
|
||||
ramdisk_target = max_pfn_mapped<<PAGE_SHIFT;
|
||||
ramdisk_here = find_e820_area(min(ramdisk_target, end_of_lowmem>>1),
|
||||
end_of_lowmem, ramdisk_size,
|
||||
PAGE_SIZE);
|
||||
ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size,
|
||||
PAGE_SIZE);
|
||||
|
||||
if (ramdisk_here == -1ULL)
|
||||
panic("Cannot find place for new RAMDISK of size %lld\n",
|
||||
|
@ -433,8 +431,12 @@ void __init setup_arch(char **cmdline_p)
|
|||
max_pfn = e820_end_of_ram();
|
||||
}
|
||||
|
||||
/* max_low_pfn get updated here */
|
||||
find_low_pfn_range();
|
||||
|
||||
/* max_pfn_mapped is updated here */
|
||||
init_memory_mapping(0, (max_low_pfn << PAGE_SHIFT));
|
||||
|
||||
reserve_initrd();
|
||||
|
||||
dmi_scan_machine();
|
||||
|
|
|
@ -57,6 +57,27 @@ unsigned long highstart_pfn, highend_pfn;
|
|||
|
||||
static noinline int do_test_wp_bit(void);
|
||||
|
||||
|
||||
static unsigned long __initdata table_start;
|
||||
static unsigned long __meminitdata table_end;
|
||||
static unsigned long __meminitdata table_top;
|
||||
|
||||
static int __initdata after_init_bootmem;
|
||||
|
||||
static __init void *alloc_low_page(unsigned long *phys)
|
||||
{
|
||||
unsigned long pfn = table_end++;
|
||||
void *adr;
|
||||
|
||||
if (pfn >= table_top)
|
||||
panic("alloc_low_page: ran out of memory");
|
||||
|
||||
adr = __va(pfn * PAGE_SIZE);
|
||||
memset(adr, 0, PAGE_SIZE);
|
||||
*phys = pfn * PAGE_SIZE;
|
||||
return adr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a middle page table and puts a pointer to it in the
|
||||
* given global directory entry. This only returns the gd entry
|
||||
|
@ -68,9 +89,12 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
|
|||
pmd_t *pmd_table;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
unsigned long phys;
|
||||
if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
|
||||
pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
|
||||
if (after_init_bootmem)
|
||||
pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
else
|
||||
pmd_table = (pmd_t *)alloc_low_page(&phys);
|
||||
paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
|
||||
set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
|
||||
pud = pud_offset(pgd, 0);
|
||||
|
@ -92,12 +116,16 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
|
|||
if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
|
||||
pte_t *page_table = NULL;
|
||||
|
||||
if (after_init_bootmem) {
|
||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||
page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
|
||||
page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
|
||||
#endif
|
||||
if (!page_table) {
|
||||
page_table =
|
||||
if (!page_table)
|
||||
page_table =
|
||||
(pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
|
||||
} else {
|
||||
unsigned long phys;
|
||||
page_table = (pte_t *)alloc_low_page(&phys);
|
||||
}
|
||||
|
||||
paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT);
|
||||
|
@ -155,7 +183,9 @@ static inline int is_kernel_text(unsigned long addr)
|
|||
* of max_low_pfn pages, by creating page tables starting from address
|
||||
* PAGE_OFFSET:
|
||||
*/
|
||||
static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
|
||||
static void __init kernel_physical_mapping_init(pgd_t *pgd_base,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
int pgd_idx, pmd_idx, pte_ofs;
|
||||
unsigned long pfn;
|
||||
|
@ -163,18 +193,19 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
|
|||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned pages_2m = 0, pages_4k = 0;
|
||||
unsigned limit_pfn = end >> PAGE_SHIFT;
|
||||
|
||||
pgd_idx = pgd_index(PAGE_OFFSET);
|
||||
pgd = pgd_base + pgd_idx;
|
||||
pfn = 0;
|
||||
pfn = start >> PAGE_SHIFT;
|
||||
|
||||
for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
|
||||
pmd = one_md_table_init(pgd);
|
||||
if (pfn >= max_low_pfn)
|
||||
if (pfn >= limit_pfn)
|
||||
continue;
|
||||
|
||||
for (pmd_idx = 0;
|
||||
pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn;
|
||||
pmd_idx < PTRS_PER_PMD && pfn < limit_pfn;
|
||||
pmd++, pmd_idx++) {
|
||||
unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET;
|
||||
|
||||
|
@ -418,20 +449,7 @@ static void __init pagetable_init(void)
|
|||
|
||||
paravirt_pagetable_setup_start(pgd_base);
|
||||
|
||||
/* Enable PSE if available */
|
||||
if (cpu_has_pse)
|
||||
set_in_cr4(X86_CR4_PSE);
|
||||
|
||||
/* Enable PGE if available */
|
||||
if (cpu_has_pge) {
|
||||
set_in_cr4(X86_CR4_PGE);
|
||||
__PAGE_KERNEL |= _PAGE_GLOBAL;
|
||||
__PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
|
||||
}
|
||||
|
||||
kernel_physical_mapping_init(pgd_base);
|
||||
remap_numa_kva();
|
||||
|
||||
/*
|
||||
* Fixed mappings, only the page table structure has to be
|
||||
* created - mappings will be set by set_fixmap():
|
||||
|
@ -703,6 +721,7 @@ void __init setup_bootmem_allocator(void)
|
|||
free_bootmem_with_active_regions(i, max_low_pfn);
|
||||
early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
|
||||
|
||||
after_init_bootmem = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -723,6 +742,77 @@ static void __init remapped_pgdat_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void __init find_early_table_space(unsigned long end)
|
||||
{
|
||||
unsigned long puds, pmds, tables, start;
|
||||
|
||||
puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
|
||||
tables = PAGE_ALIGN(puds * sizeof(pud_t));
|
||||
|
||||
pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
|
||||
tables += PAGE_ALIGN(pmds * sizeof(pmd_t));
|
||||
|
||||
/*
|
||||
* RED-PEN putting page tables only on node 0 could
|
||||
* cause a hotspot and fill up ZONE_DMA. The page tables
|
||||
* need roughly 0.5KB per GB.
|
||||
*/
|
||||
start = 0x7000;
|
||||
table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
|
||||
tables, PAGE_SIZE);
|
||||
if (table_start == -1UL)
|
||||
panic("Cannot find space for the kernel page tables");
|
||||
|
||||
table_start >>= PAGE_SHIFT;
|
||||
table_end = table_start;
|
||||
table_top = table_start + (tables>>PAGE_SHIFT);
|
||||
|
||||
printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
|
||||
end, table_start << PAGE_SHIFT,
|
||||
(table_start << PAGE_SHIFT) + tables);
|
||||
}
|
||||
|
||||
unsigned long __init_refok init_memory_mapping(unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
pgd_t *pgd_base = swapper_pg_dir;
|
||||
|
||||
/*
|
||||
* Find space for the kernel direct mapping tables.
|
||||
*/
|
||||
if (!after_init_bootmem)
|
||||
find_early_table_space(end);
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
set_nx();
|
||||
if (nx_enabled)
|
||||
printk(KERN_INFO "NX (Execute Disable) protection: active\n");
|
||||
#endif
|
||||
|
||||
/* Enable PSE if available */
|
||||
if (cpu_has_pse)
|
||||
set_in_cr4(X86_CR4_PSE);
|
||||
|
||||
/* Enable PGE if available */
|
||||
if (cpu_has_pge) {
|
||||
set_in_cr4(X86_CR4_PGE);
|
||||
__PAGE_KERNEL |= _PAGE_GLOBAL;
|
||||
__PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
|
||||
}
|
||||
|
||||
kernel_physical_mapping_init(pgd_base, start, end);
|
||||
|
||||
load_cr3(swapper_pg_dir);
|
||||
|
||||
__flush_tlb_all();
|
||||
|
||||
if (!after_init_bootmem)
|
||||
reserve_early(table_start << PAGE_SHIFT,
|
||||
table_end << PAGE_SHIFT, "PGTABLE");
|
||||
|
||||
return end >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* paging_init() sets up the page tables - note that the first 8MB are
|
||||
* already mapped by head.S.
|
||||
|
@ -732,15 +822,8 @@ static void __init remapped_pgdat_init(void)
|
|||
*/
|
||||
void __init paging_init(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_PAE
|
||||
set_nx();
|
||||
if (nx_enabled)
|
||||
printk(KERN_INFO "NX (Execute Disable) protection: active\n");
|
||||
#endif
|
||||
pagetable_init();
|
||||
|
||||
load_cr3(swapper_pg_dir);
|
||||
|
||||
__flush_tlb_all();
|
||||
|
||||
kmap_init();
|
||||
|
|
|
@ -93,6 +93,8 @@ extern int sysctl_legacy_va_layout;
|
|||
#define MAXMEM (-__PAGE_OFFSET - __VMALLOC_RESERVE)
|
||||
|
||||
extern void find_low_pfn_range(void);
|
||||
extern unsigned long init_memory_mapping(unsigned long start,
|
||||
unsigned long end);
|
||||
extern void initmem_init(unsigned long, unsigned long);
|
||||
extern void zone_sizes_init(void);
|
||||
extern void setup_bootmem_allocator(void);
|
||||
|
|
Loading…
Reference in a new issue