Commit 84e6ffb2 authored by Mike Rapoport's avatar Mike Rapoport Committed by Linus Torvalds

arm: add support for folded p4d page tables

Implement primitives necessary for the 4th level folding, add walks of p4d
level where appropriate, and remove __ARCH_USE_5LEVEL_HACK.

[rppt@linux.ibm.com: fix kexec]
  Link: http://lkml.kernel.org/r/20200508174232.GA759899@linux.ibm.comSigned-off-by: default avatarMike Rapoport <rppt@linux.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Tested-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Brian Cain <bcain@codeaurora.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christophe Leroy <christophe.leroy@c-s.fr>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Guan Xuetao <gxt@pku.edu.cn>
Cc: James Morse <james.morse@arm.com>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Julien Thierry <julien.thierry.kdev@gmail.com>
Cc: Ley Foon Tan <ley.foon.tan@intel.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Link: http://lkml.kernel.org/r/20200414153455.21744-3-rppt@kernel.orgSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f426f4ed
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#else #else
#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopud.h> #include <asm-generic/pgtable-nopud.h>
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/pgtable-hwdef.h> #include <asm/pgtable-hwdef.h>
......
...@@ -24,6 +24,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) ...@@ -24,6 +24,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
{ {
unsigned long addr = (unsigned long)_addr; unsigned long addr = (unsigned long)_addr;
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
pud_t *pud; pud_t *pud;
...@@ -33,7 +34,11 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) ...@@ -33,7 +34,11 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd))) if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
return 0; return 0;
pud = pud_offset(pgd, addr); p4d = p4d_offset(pgd, addr);
if (unlikely(p4d_none(*p4d) || p4d_bad(*p4d)))
return 0;
pud = pud_offset(p4d, addr);
if (unlikely(pud_none(*pud) || pud_bad(*pud))) if (unlikely(pud_none(*pud) || pud_bad(*pud)))
return 0; return 0;
......
...@@ -633,7 +633,7 @@ static void __init map_sa1100_gpio_regs( void ) ...@@ -633,7 +633,7 @@ static void __init map_sa1100_gpio_regs( void )
int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO); int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
pmd_t *pmd; pmd_t *pmd;
pmd = pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); pmd = pmd_offset(pud_offset(p4d_offset(pgd_offset_k(virt), virt), virt), virt);
*pmd = __pmd(phys | prot); *pmd = __pmd(phys | prot);
flush_pmd_entry(pmd); flush_pmd_entry(pmd);
} }
......
...@@ -207,6 +207,7 @@ struct pg_level { ...@@ -207,6 +207,7 @@ struct pg_level {
static struct pg_level pg_level[] = { static struct pg_level pg_level[] = {
{ {
}, { /* pgd */ }, { /* pgd */
}, { /* p4d */
}, { /* pud */ }, { /* pud */
}, { /* pmd */ }, { /* pmd */
.bits = section_bits, .bits = section_bits,
...@@ -308,7 +309,7 @@ static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start, ...@@ -308,7 +309,7 @@ static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start,
for (i = 0; i < PTRS_PER_PTE; i++, pte++) { for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
addr = start + i * PAGE_SIZE; addr = start + i * PAGE_SIZE;
note_page(st, addr, 4, pte_val(*pte), domain); note_page(st, addr, 5, pte_val(*pte), domain);
} }
} }
...@@ -350,14 +351,14 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) ...@@ -350,14 +351,14 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
addr += SECTION_SIZE; addr += SECTION_SIZE;
pmd++; pmd++;
domain = get_domain_name(pmd); domain = get_domain_name(pmd);
note_page(st, addr, 3, pmd_val(*pmd), domain); note_page(st, addr, 4, pmd_val(*pmd), domain);
} }
} }
} }
static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) static void walk_pud(struct pg_state *st, p4d_t *p4d, unsigned long start)
{ {
pud_t *pud = pud_offset(pgd, 0); pud_t *pud = pud_offset(p4d, 0);
unsigned long addr; unsigned long addr;
unsigned i; unsigned i;
...@@ -366,7 +367,23 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) ...@@ -366,7 +367,23 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
if (!pud_none(*pud)) { if (!pud_none(*pud)) {
walk_pmd(st, pud, addr); walk_pmd(st, pud, addr);
} else { } else {
note_page(st, addr, 2, pud_val(*pud), NULL); note_page(st, addr, 3, pud_val(*pud), NULL);
}
}
}
static void walk_p4d(struct pg_state *st, pgd_t *pgd, unsigned long start)
{
p4d_t *p4d = p4d_offset(pgd, 0);
unsigned long addr;
unsigned i;
for (i = 0; i < PTRS_PER_P4D; i++, p4d++) {
addr = start + i * P4D_SIZE;
if (!p4d_none(*p4d)) {
walk_pud(st, p4d, addr);
} else {
note_page(st, addr, 2, p4d_val(*p4d), NULL);
} }
} }
} }
...@@ -381,7 +398,7 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm, ...@@ -381,7 +398,7 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
addr = start + i * PGDIR_SIZE; addr = start + i * PGDIR_SIZE;
if (!pgd_none(*pgd)) { if (!pgd_none(*pgd)) {
walk_pud(st, pgd, addr); walk_p4d(st, pgd, addr);
} else { } else {
note_page(st, addr, 1, pgd_val(*pgd), NULL); note_page(st, addr, 1, pgd_val(*pgd), NULL);
} }
......
...@@ -91,6 +91,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, ...@@ -91,6 +91,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
{ {
spinlock_t *ptl; spinlock_t *ptl;
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
...@@ -100,7 +101,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, ...@@ -100,7 +101,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
if (pgd_none_or_clear_bad(pgd)) if (pgd_none_or_clear_bad(pgd))
return 0; return 0;
pud = pud_offset(pgd, address); p4d = p4d_offset(pgd, address);
if (p4d_none_or_clear_bad(p4d))
return 0;
pud = pud_offset(p4d, address);
if (pud_none_or_clear_bad(pud)) if (pud_none_or_clear_bad(pud))
return 0; return 0;
......
...@@ -43,19 +43,21 @@ void show_pte(const char *lvl, struct mm_struct *mm, unsigned long addr) ...@@ -43,19 +43,21 @@ void show_pte(const char *lvl, struct mm_struct *mm, unsigned long addr)
printk("%s[%08lx] *pgd=%08llx", lvl, addr, (long long)pgd_val(*pgd)); printk("%s[%08lx] *pgd=%08llx", lvl, addr, (long long)pgd_val(*pgd));
do { do {
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
if (pgd_none(*pgd)) p4d = p4d_offset(pgd, addr);
if (p4d_none(*p4d))
break; break;
if (pgd_bad(*pgd)) { if (p4d_bad(*p4d)) {
pr_cont("(bad)"); pr_cont("(bad)");
break; break;
} }
pud = pud_offset(pgd, addr); pud = pud_offset(p4d, addr);
if (PTRS_PER_PUD != 1) if (PTRS_PER_PUD != 1)
pr_cont(", *pud=%08llx", (long long)pud_val(*pud)); pr_cont(", *pud=%08llx", (long long)pud_val(*pud));
...@@ -405,6 +407,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr, ...@@ -405,6 +407,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
{ {
unsigned int index; unsigned int index;
pgd_t *pgd, *pgd_k; pgd_t *pgd, *pgd_k;
p4d_t *p4d, *p4d_k;
pud_t *pud, *pud_k; pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k; pmd_t *pmd, *pmd_k;
...@@ -419,13 +422,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr, ...@@ -419,13 +422,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
pgd = cpu_get_pgd() + index; pgd = cpu_get_pgd() + index;
pgd_k = init_mm.pgd + index; pgd_k = init_mm.pgd + index;
if (pgd_none(*pgd_k)) p4d = p4d_offset(pgd, addr);
p4d_k = p4d_offset(pgd_k, addr);
if (p4d_none(*p4d_k))
goto bad_area; goto bad_area;
if (!pgd_present(*pgd)) if (!p4d_present(*p4d))
set_pgd(pgd, *pgd_k); set_p4d(p4d, *p4d_k);
pud = pud_offset(pgd, addr); pud = pud_offset(p4d, addr);
pud_k = pud_offset(pgd_k, addr); pud_k = pud_offset(p4d_k, addr);
if (pud_none(*pud_k)) if (pud_none(*pud_k))
goto bad_area; goto bad_area;
......
...@@ -68,7 +68,8 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end, ...@@ -68,7 +68,8 @@ static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
unsigned long prot) unsigned long prot)
{ {
pud_t *pud = pud_offset(pgd, addr); p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
unsigned long next; unsigned long next;
do { do {
......
...@@ -519,7 +519,7 @@ static inline void section_update(unsigned long addr, pmdval_t mask, ...@@ -519,7 +519,7 @@ static inline void section_update(unsigned long addr, pmdval_t mask,
{ {
pmd_t *pmd; pmd_t *pmd;
pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr); pmd = pmd_offset(pud_offset(p4d_offset(pgd_offset(mm, addr), addr), addr), addr);
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot); pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot);
......
...@@ -142,12 +142,14 @@ static void unmap_area_sections(unsigned long virt, unsigned long size) ...@@ -142,12 +142,14 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
{ {
unsigned long addr = virt, end = virt + (size & ~(SZ_1M - 1)); unsigned long addr = virt, end = virt + (size & ~(SZ_1M - 1));
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmdp; pmd_t *pmdp;
flush_cache_vunmap(addr, end); flush_cache_vunmap(addr, end);
pgd = pgd_offset_k(addr); pgd = pgd_offset_k(addr);
pud = pud_offset(pgd, addr); p4d = p4d_offset(pgd, addr);
pud = pud_offset(p4d, addr);
pmdp = pmd_offset(pud, addr); pmdp = pmd_offset(pud, addr);
do { do {
pmd_t pmd = *pmdp; pmd_t pmd = *pmdp;
...@@ -190,6 +192,7 @@ remap_area_sections(unsigned long virt, unsigned long pfn, ...@@ -190,6 +192,7 @@ remap_area_sections(unsigned long virt, unsigned long pfn,
{ {
unsigned long addr = virt, end = virt + size; unsigned long addr = virt, end = virt + size;
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
...@@ -200,7 +203,8 @@ remap_area_sections(unsigned long virt, unsigned long pfn, ...@@ -200,7 +203,8 @@ remap_area_sections(unsigned long virt, unsigned long pfn,
unmap_area_sections(virt, size); unmap_area_sections(virt, size);
pgd = pgd_offset_k(addr); pgd = pgd_offset_k(addr);
pud = pud_offset(pgd, addr); p4d = p4d_offset(pgd, addr);
pud = pud_offset(p4d, addr);
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
do { do {
pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect); pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
...@@ -222,6 +226,7 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, ...@@ -222,6 +226,7 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
{ {
unsigned long addr = virt, end = virt + size; unsigned long addr = virt, end = virt + size;
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
...@@ -232,7 +237,8 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, ...@@ -232,7 +237,8 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
unmap_area_sections(virt, size); unmap_area_sections(virt, size);
pgd = pgd_offset_k(virt); pgd = pgd_offset_k(virt);
pud = pud_offset(pgd, addr); p4d = p4d_offset(pgd, addr);
pud = pud_offset(p4d, addr);
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
do { do {
unsigned long super_pmd_val, i; unsigned long super_pmd_val, i;
......
...@@ -38,7 +38,7 @@ static inline pte_t get_top_pte(unsigned long va) ...@@ -38,7 +38,7 @@ static inline pte_t get_top_pte(unsigned long va)
static inline pmd_t *pmd_off_k(unsigned long virt) static inline pmd_t *pmd_off_k(unsigned long virt)
{ {
return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); return pmd_offset(pud_offset(p4d_offset(pgd_offset_k(virt), virt), virt), virt);
} }
struct mem_type { struct mem_type {
......
...@@ -357,7 +357,8 @@ static pte_t *pte_offset_late_fixmap(pmd_t *dir, unsigned long addr) ...@@ -357,7 +357,8 @@ static pte_t *pte_offset_late_fixmap(pmd_t *dir, unsigned long addr)
static inline pmd_t * __init fixmap_pmd(unsigned long addr) static inline pmd_t * __init fixmap_pmd(unsigned long addr)
{ {
pgd_t *pgd = pgd_offset_k(addr); pgd_t *pgd = pgd_offset_k(addr);
pud_t *pud = pud_offset(pgd, addr); p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
pmd_t *pmd = pmd_offset(pud, addr); pmd_t *pmd = pmd_offset(pud, addr);
return pmd; return pmd;
...@@ -801,12 +802,12 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, ...@@ -801,12 +802,12 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
} while (pmd++, addr = next, addr != end); } while (pmd++, addr = next, addr != end);
} }
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, static void __init alloc_init_pud(p4d_t *p4d, unsigned long addr,
unsigned long end, phys_addr_t phys, unsigned long end, phys_addr_t phys,
const struct mem_type *type, const struct mem_type *type,
void *(*alloc)(unsigned long sz), bool ng) void *(*alloc)(unsigned long sz), bool ng)
{ {
pud_t *pud = pud_offset(pgd, addr); pud_t *pud = pud_offset(p4d, addr);
unsigned long next; unsigned long next;
do { do {
...@@ -816,6 +817,21 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, ...@@ -816,6 +817,21 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
} while (pud++, addr = next, addr != end); } while (pud++, addr = next, addr != end);
} }
static void __init alloc_init_p4d(pgd_t *pgd, unsigned long addr,
unsigned long end, phys_addr_t phys,
const struct mem_type *type,
void *(*alloc)(unsigned long sz), bool ng)
{
p4d_t *p4d = p4d_offset(pgd, addr);
unsigned long next;
do {
next = p4d_addr_end(addr, end);
alloc_init_pud(p4d, addr, next, phys, type, alloc, ng);
phys += next - addr;
} while (p4d++, addr = next, addr != end);
}
#ifndef CONFIG_ARM_LPAE #ifndef CONFIG_ARM_LPAE
static void __init create_36bit_mapping(struct mm_struct *mm, static void __init create_36bit_mapping(struct mm_struct *mm,
struct map_desc *md, struct map_desc *md,
...@@ -863,7 +879,8 @@ static void __init create_36bit_mapping(struct mm_struct *mm, ...@@ -863,7 +879,8 @@ static void __init create_36bit_mapping(struct mm_struct *mm,
pgd = pgd_offset(mm, addr); pgd = pgd_offset(mm, addr);
end = addr + length; end = addr + length;
do { do {
pud_t *pud = pud_offset(pgd, addr); p4d_t *p4d = p4d_offset(pgd, addr);
pud_t *pud = pud_offset(p4d, addr);
pmd_t *pmd = pmd_offset(pud, addr); pmd_t *pmd = pmd_offset(pud, addr);
int i; int i;
...@@ -914,7 +931,7 @@ static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md, ...@@ -914,7 +931,7 @@ static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
do { do {
unsigned long next = pgd_addr_end(addr, end); unsigned long next = pgd_addr_end(addr, end);
alloc_init_pud(pgd, addr, next, phys, type, alloc, ng); alloc_init_p4d(pgd, addr, next, phys, type, alloc, ng);
phys += next - addr; phys += next - addr;
addr = next; addr = next;
...@@ -950,7 +967,13 @@ void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md, ...@@ -950,7 +967,13 @@ void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md,
bool ng) bool ng)
{ {
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
pud_t *pud = pud_alloc(mm, pgd_offset(mm, md->virtual), md->virtual); p4d_t *p4d;
pud_t *pud;
p4d = p4d_alloc(mm, pgd_offset(mm, md->virtual), md->virtual);
if (!WARN_ON(!p4d))
return;
pud = pud_alloc(mm, p4d, md->virtual);
if (WARN_ON(!pud)) if (WARN_ON(!pud))
return; return;
pmd_alloc(mm, pud, 0); pmd_alloc(mm, pud, 0);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
pgd_t *pgd_alloc(struct mm_struct *mm) pgd_t *pgd_alloc(struct mm_struct *mm)
{ {
pgd_t *new_pgd, *init_pgd; pgd_t *new_pgd, *init_pgd;
p4d_t *new_p4d, *init_p4d;
pud_t *new_pud, *init_pud; pud_t *new_pud, *init_pud;
pmd_t *new_pmd, *init_pmd; pmd_t *new_pmd, *init_pmd;
pte_t *new_pte, *init_pte; pte_t *new_pte, *init_pte;
...@@ -53,8 +54,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm) ...@@ -53,8 +54,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
/* /*
* Allocate PMD table for modules and pkmap mappings. * Allocate PMD table for modules and pkmap mappings.
*/ */
new_pud = pud_alloc(mm, new_pgd + pgd_index(MODULES_VADDR), new_p4d = p4d_alloc(mm, new_pgd + pgd_index(MODULES_VADDR),
MODULES_VADDR); MODULES_VADDR);
if (!new_p4d)
goto no_p4d;
new_pud = pud_alloc(mm, new_p4d, MODULES_VADDR);
if (!new_pud) if (!new_pud)
goto no_pud; goto no_pud;
...@@ -69,7 +74,11 @@ pgd_t *pgd_alloc(struct mm_struct *mm) ...@@ -69,7 +74,11 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
* contains the machine vectors. The vectors are always high * contains the machine vectors. The vectors are always high
* with LPAE. * with LPAE.
*/ */
new_pud = pud_alloc(mm, new_pgd, 0); new_p4d = p4d_alloc(mm, new_pgd, 0);
if (!new_p4d)
goto no_p4d;
new_pud = pud_alloc(mm, new_p4d, 0);
if (!new_pud) if (!new_pud)
goto no_pud; goto no_pud;
...@@ -91,7 +100,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm) ...@@ -91,7 +100,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
pmd_val(*new_pmd) |= PMD_DOMAIN(DOMAIN_VECTORS); pmd_val(*new_pmd) |= PMD_DOMAIN(DOMAIN_VECTORS);
#endif #endif
init_pud = pud_offset(init_pgd, 0); init_p4d = p4d_offset(init_pgd, 0);
init_pud = pud_offset(init_p4d, 0);
init_pmd = pmd_offset(init_pud, 0); init_pmd = pmd_offset(init_pud, 0);
init_pte = pte_offset_map(init_pmd, 0); init_pte = pte_offset_map(init_pmd, 0);
set_pte_ext(new_pte + 0, init_pte[0], 0); set_pte_ext(new_pte + 0, init_pte[0], 0);
...@@ -108,6 +118,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm) ...@@ -108,6 +118,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
no_pmd: no_pmd:
pud_free(mm, new_pud); pud_free(mm, new_pud);
no_pud: no_pud:
p4d_free(mm, new_p4d);
no_p4d:
__pgd_free(new_pgd); __pgd_free(new_pgd);
no_pgd: no_pgd:
return NULL; return NULL;
...@@ -116,6 +128,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) ...@@ -116,6 +128,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
{ {
pgd_t *pgd; pgd_t *pgd;
p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pgtable_t pte; pgtable_t pte;
...@@ -127,7 +140,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) ...@@ -127,7 +140,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
if (pgd_none_or_clear_bad(pgd)) if (pgd_none_or_clear_bad(pgd))
goto no_pgd; goto no_pgd;
pud = pud_offset(pgd, 0); p4d = p4d_offset(pgd, 0);
if (p4d_none_or_clear_bad(p4d))
goto no_p4d;
pud = pud_offset(p4d, 0);
if (pud_none_or_clear_bad(pud)) if (pud_none_or_clear_bad(pud))
goto no_pud; goto no_pud;
...@@ -144,8 +161,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) ...@@ -144,8 +161,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
pmd_free(mm, pmd); pmd_free(mm, pmd);
mm_dec_nr_pmds(mm); mm_dec_nr_pmds(mm);
no_pud: no_pud:
pgd_clear(pgd); p4d_clear(p4d);
pud_free(mm, pud); pud_free(mm, pud);
no_p4d:
pgd_clear(pgd);
p4d_free(mm, p4d);
no_pgd: no_pgd:
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
/* /*
...@@ -156,15 +176,21 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) ...@@ -156,15 +176,21 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
continue; continue;
if (pgd_val(*pgd) & L_PGD_SWAPPER) if (pgd_val(*pgd) & L_PGD_SWAPPER)
continue; continue;
pud = pud_offset(pgd, 0); p4d = p4d_offset(pgd, 0);
if (p4d_none_or_clear_bad(p4d))
continue;
pud = pud_offset(p4d, 0);
if (pud_none_or_clear_bad(pud)) if (pud_none_or_clear_bad(pud))
continue; continue;
pmd = pmd_offset(pud, 0); pmd = pmd_offset(pud, 0);
pud_clear(pud); pud_clear(pud);
pmd_free(mm, pmd); pmd_free(mm, pmd);
mm_dec_nr_pmds(mm); mm_dec_nr_pmds(mm);
pgd_clear(pgd); p4d_clear(p4d);
pud_free(mm, pud); pud_free(mm, pud);
mm_dec_nr_puds(mm);
pgd_clear(pgd);
p4d_free(mm, p4d);
} }
#endif #endif
__pgd_free(pgd_base); __pgd_free(pgd_base);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment