in mm/init_64.c [1758:1855]
static unsigned long __ref kernel_map_range(unsigned long pstart,
unsigned long pend, pgprot_t prot,
bool use_huge)
{
unsigned long vstart = PAGE_OFFSET + pstart;
unsigned long vend = PAGE_OFFSET + pend;
unsigned long alloc_bytes = 0UL;
if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) {
prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n",
vstart, vend);
prom_halt();
}
while (vstart < vend) {
unsigned long this_end, paddr = __pa(vstart);
pgd_t *pgd = pgd_offset_k(vstart);
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (pgd_none(*pgd)) {
pud_t *new;
new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
PAGE_SIZE);
if (!new)
goto err_alloc;
alloc_bytes += PAGE_SIZE;
pgd_populate(&init_mm, pgd, new);
}
p4d = p4d_offset(pgd, vstart);
if (p4d_none(*p4d)) {
pud_t *new;
new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
PAGE_SIZE);
if (!new)
goto err_alloc;
alloc_bytes += PAGE_SIZE;
p4d_populate(&init_mm, p4d, new);
}
pud = pud_offset(p4d, vstart);
if (pud_none(*pud)) {
pmd_t *new;
if (kernel_can_map_hugepud(vstart, vend, use_huge)) {
vstart = kernel_map_hugepud(vstart, vend, pud);
continue;
}
new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
PAGE_SIZE);
if (!new)
goto err_alloc;
alloc_bytes += PAGE_SIZE;
pud_populate(&init_mm, pud, new);
}
pmd = pmd_offset(pud, vstart);
if (pmd_none(*pmd)) {
pte_t *new;
if (kernel_can_map_hugepmd(vstart, vend, use_huge)) {
vstart = kernel_map_hugepmd(vstart, vend, pmd);
continue;
}
new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE,
PAGE_SIZE);
if (!new)
goto err_alloc;
alloc_bytes += PAGE_SIZE;
pmd_populate_kernel(&init_mm, pmd, new);
}
pte = pte_offset_kernel(pmd, vstart);
this_end = (vstart + PMD_SIZE) & PMD_MASK;
if (this_end > vend)
this_end = vend;
while (vstart < this_end) {
pte_val(*pte) = (paddr | pgprot_val(prot));
vstart += PAGE_SIZE;
paddr += PAGE_SIZE;
pte++;
}
}
return alloc_bytes;
err_alloc:
panic("%s: Failed to allocate %lu bytes align=%lx from=%lx\n",
__func__, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
return -ENOMEM;
}