Skip to content

Commit e19f97e

Browse files
rppttorvalds
authored andcommitted
um: add support for folded p4d page tables
The UML port uses 4 and 5 level fixups to support higher level page table directories in the generic VM code. Implement primitives necessary for the 4th level folding, add walks of p4d level where appropriate and drop usage of __ARCH_USE_5LEVEL_HACK. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Mike Rapoport <[email protected]> Cc: Anatoly Pugachev <[email protected]> Cc: Anton Ivanov <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: Greentime Hu <[email protected]> Cc: Greg Ungerer <[email protected]> Cc: Helge Deller <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Jeff Dike <[email protected]> Cc: "Kirill A. Shutemov" <[email protected]> Cc: Mark Salter <[email protected]> Cc: Matt Turner <[email protected]> Cc: Michal Simek <[email protected]> Cc: Peter Rosin <[email protected]> Cc: Richard Weinberger <[email protected]> Cc: Rolf Eike Beer <[email protected]> Cc: Russell King <[email protected]> Cc: Russell King <[email protected]> Cc: Sam Creasey <[email protected]> Cc: Vincent Chen <[email protected]> Cc: Vineet Gupta <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4e65e76 commit e19f97e

File tree

8 files changed

+78
-14
lines changed

8 files changed

+78
-14
lines changed

arch/um/include/asm/pgtable-2level.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#ifndef __UM_PGTABLE_2LEVEL_H
99
#define __UM_PGTABLE_2LEVEL_H
1010

11-
#define __ARCH_USE_5LEVEL_HACK
1211
#include <asm-generic/pgtable-nopmd.h>
1312

1413
/* PGDIR_SHIFT determines what a third-level page table entry can map */

arch/um/include/asm/pgtable-3level.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#ifndef __UM_PGTABLE_3LEVEL_H
88
#define __UM_PGTABLE_3LEVEL_H
99

10-
#define __ARCH_USE_5LEVEL_HACK
1110
#include <asm-generic/pgtable-nopud.h>
1211

1312
/* PGDIR_SHIFT determines what a third-level page table entry can map */

arch/um/include/asm/pgtable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ extern unsigned long end_iomem;
106106
#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE)
107107
#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE)
108108

109+
#define p4d_newpage(x) (p4d_val(x) & _PAGE_NEWPAGE)
110+
#define p4d_mkuptodate(x) (p4d_val(x) &= ~_PAGE_NEWPAGE)
111+
109112
#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
110113

111114
#define pte_page(x) pfn_to_page(pte_pfn(x))

arch/um/kernel/mem.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
9696
pgd_t *pgd_base)
9797
{
9898
pgd_t *pgd;
99+
p4d_t *p4d;
99100
pud_t *pud;
100101
pmd_t *pmd;
101102
int i, j;
@@ -107,7 +108,8 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
107108
pgd = pgd_base + i;
108109

109110
for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
110-
pud = pud_offset(pgd, vaddr);
111+
p4d = p4d_offset(pgd, vaddr);
112+
pud = pud_offset(p4d, vaddr);
111113
if (pud_none(*pud))
112114
one_md_table_init(pud);
113115
pmd = pmd_offset(pud, vaddr);
@@ -124,6 +126,7 @@ static void __init fixaddr_user_init( void)
124126
#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
125127
long size = FIXADDR_USER_END - FIXADDR_USER_START;
126128
pgd_t *pgd;
129+
p4d_t *p4d;
127130
pud_t *pud;
128131
pmd_t *pmd;
129132
pte_t *pte;
@@ -144,7 +147,8 @@ static void __init fixaddr_user_init( void)
144147
for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
145148
p += PAGE_SIZE) {
146149
pgd = swapper_pg_dir + pgd_index(vaddr);
147-
pud = pud_offset(pgd, vaddr);
150+
p4d = p4d_offset(pgd, vaddr);
151+
pud = pud_offset(p4d, vaddr);
148152
pmd = pmd_offset(pud, vaddr);
149153
pte = pte_offset_kernel(pmd, vaddr);
150154
pte_set_val(*pte, p, PAGE_READONLY);

arch/um/kernel/skas/mmu.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
1919
unsigned long kernel)
2020
{
2121
pgd_t *pgd;
22+
p4d_t *p4d;
2223
pud_t *pud;
2324
pmd_t *pmd;
2425
pte_t *pte;
2526

2627
pgd = pgd_offset(mm, proc);
27-
pud = pud_alloc(mm, pgd, proc);
28-
if (!pud)
28+
29+
p4d = p4d_alloc(mm, pgd, proc);
30+
if (!p4d)
2931
goto out;
3032

33+
pud = pud_alloc(mm, p4d, proc);
34+
if (!pud)
35+
goto out_pud;
36+
3137
pmd = pmd_alloc(mm, pud, proc);
3238
if (!pmd)
3339
goto out_pmd;
@@ -44,6 +50,8 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
4450
pmd_free(mm, pmd);
4551
out_pmd:
4652
pud_free(mm, pud);
53+
out_pud:
54+
p4d_free(mm, p4d);
4755
out:
4856
return -ENOMEM;
4957
}

arch/um/kernel/skas/uaccess.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
1818
{
1919
pgd_t *pgd;
20+
p4d_t *p4d;
2021
pud_t *pud;
2122
pmd_t *pmd;
2223

@@ -27,7 +28,11 @@ pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
2728
if (!pgd_present(*pgd))
2829
return NULL;
2930

30-
pud = pud_offset(pgd, addr);
31+
p4d = p4d_offset(pgd, addr);
32+
if (!p4d_present(*p4d))
33+
return NULL;
34+
35+
pud = pud_offset(p4d, addr);
3136
if (!pud_present(*pud))
3237
return NULL;
3338

arch/um/kernel/tlb.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,15 @@ static inline int update_pmd_range(pud_t *pud, unsigned long addr,
277277
return ret;
278278
}
279279

280-
static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
280+
static inline int update_pud_range(p4d_t *p4d, unsigned long addr,
281281
unsigned long end,
282282
struct host_vm_change *hvc)
283283
{
284284
pud_t *pud;
285285
unsigned long next;
286286
int ret = 0;
287287

288-
pud = pud_offset(pgd, addr);
288+
pud = pud_offset(p4d, addr);
289289
do {
290290
next = pud_addr_end(addr, end);
291291
if (!pud_present(*pud)) {
@@ -299,6 +299,28 @@ static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
299299
return ret;
300300
}
301301

302+
static inline int update_p4d_range(pgd_t *pgd, unsigned long addr,
303+
unsigned long end,
304+
struct host_vm_change *hvc)
305+
{
306+
p4d_t *p4d;
307+
unsigned long next;
308+
int ret = 0;
309+
310+
p4d = p4d_offset(pgd, addr);
311+
do {
312+
next = p4d_addr_end(addr, end);
313+
if (!p4d_present(*p4d)) {
314+
if (hvc->force || p4d_newpage(*p4d)) {
315+
ret = add_munmap(addr, next - addr, hvc);
316+
p4d_mkuptodate(*p4d);
317+
}
318+
} else
319+
ret = update_pud_range(p4d, addr, next, hvc);
320+
} while (p4d++, addr = next, ((addr < end) && !ret));
321+
return ret;
322+
}
323+
302324
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
303325
unsigned long end_addr, int force)
304326
{
@@ -316,8 +338,8 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
316338
ret = add_munmap(addr, next - addr, &hvc);
317339
pgd_mkuptodate(*pgd);
318340
}
319-
}
320-
else ret = update_pud_range(pgd, addr, next, &hvc);
341+
} else
342+
ret = update_p4d_range(pgd, addr, next, &hvc);
321343
} while (pgd++, addr = next, ((addr < end_addr) && !ret));
322344

323345
if (!ret)
@@ -338,6 +360,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
338360
{
339361
struct mm_struct *mm;
340362
pgd_t *pgd;
363+
p4d_t *p4d;
341364
pud_t *pud;
342365
pmd_t *pmd;
343366
pte_t *pte;
@@ -364,7 +387,23 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
364387
continue;
365388
}
366389

367-
pud = pud_offset(pgd, addr);
390+
p4d = p4d_offset(pgd, addr);
391+
if (!p4d_present(*p4d)) {
392+
last = ADD_ROUND(addr, P4D_SIZE);
393+
if (last > end)
394+
last = end;
395+
if (p4d_newpage(*p4d)) {
396+
updated = 1;
397+
err = add_munmap(addr, last - addr, &hvc);
398+
if (err < 0)
399+
panic("munmap failed, errno = %d\n",
400+
-err);
401+
}
402+
addr = last;
403+
continue;
404+
}
405+
406+
pud = pud_offset(p4d, addr);
368407
if (!pud_present(*pud)) {
369408
last = ADD_ROUND(addr, PUD_SIZE);
370409
if (last > end)
@@ -424,6 +463,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
424463
void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
425464
{
426465
pgd_t *pgd;
466+
p4d_t *p4d;
427467
pud_t *pud;
428468
pmd_t *pmd;
429469
pte_t *pte;
@@ -437,7 +477,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
437477
if (!pgd_present(*pgd))
438478
goto kill;
439479

440-
pud = pud_offset(pgd, address);
480+
p4d = p4d_offset(pgd, address);
481+
if (!p4d_present(*p4d))
482+
goto kill;
483+
484+
pud = pud_offset(p4d, address);
441485
if (!pud_present(*pud))
442486
goto kill;
443487

arch/um/kernel/trap.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
2828
struct mm_struct *mm = current->mm;
2929
struct vm_area_struct *vma;
3030
pgd_t *pgd;
31+
p4d_t *p4d;
3132
pud_t *pud;
3233
pmd_t *pmd;
3334
pte_t *pte;
@@ -104,7 +105,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
104105
}
105106

106107
pgd = pgd_offset(mm, address);
107-
pud = pud_offset(pgd, address);
108+
p4d = p4d_offset(pgd, address);
109+
pud = pud_offset(p4d, address);
108110
pmd = pmd_offset(pud, address);
109111
pte = pte_offset_kernel(pmd, address);
110112
} while (!pte_present(*pte));

0 commit comments

Comments
 (0)