Skip to content

Commit d9e9a64

Browse files
hansendcIngo Molnar
authored andcommitted
x86/mm/pti: Allocate a separate user PGD
Kernel page table isolation requires to have two PGDs. One for the kernel, which contains the full kernel mapping plus the user space mapping and one for user space which contains the user space mappings and the minimal set of kernel mappings which are required by the architecture to be able to transition from and to user space. Add the necessary preliminaries. [ tglx: Split out from the big kaiser dump. EFI fixup from Kirill ] Signed-off-by: Dave Hansen <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Borislav Petkov <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Boris Ostrovsky <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: David Laight <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: Eduardo Valentin <[email protected]> Cc: Greg KH <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Juergen Gross <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Will Deacon <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 1c4de1f commit d9e9a64

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

arch/x86/include/asm/pgalloc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ static inline void paravirt_release_p4d(unsigned long pfn) {}
3030
*/
3131
extern gfp_t __userpte_alloc_gfp;
3232

33+
#ifdef CONFIG_PAGE_TABLE_ISOLATION
34+
/*
35+
* Instead of one PGD, we acquire two PGDs. Being order-1, it is
36+
* both 8k in size and 8k-aligned. That lets us just flip bit 12
37+
* in a pointer to swap between the two 4k halves.
38+
*/
39+
#define PGD_ALLOCATION_ORDER 1
40+
#else
41+
#define PGD_ALLOCATION_ORDER 0
42+
#endif
43+
3344
/*
3445
* Allocate and free page tables.
3546
*/

arch/x86/kernel/head_64.S

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,27 @@ GLOBAL(early_recursion_flag)
341341
.balign PAGE_SIZE; \
342342
GLOBAL(name)
343343

344+
#ifdef CONFIG_PAGE_TABLE_ISOLATION
345+
/*
346+
* Each PGD needs to be 8k long and 8k aligned. We do not
347+
* ever go out to userspace with these, so we do not
348+
* strictly *need* the second page, but this allows us to
349+
* have a single set_pgd() implementation that does not
350+
* need to worry about whether it has 4k or 8k to work
351+
* with.
352+
*
353+
* This ensures PGDs are 8k long:
354+
*/
355+
#define PTI_USER_PGD_FILL 512
356+
/* This ensures they are 8k-aligned: */
357+
#define NEXT_PGD_PAGE(name) \
358+
.balign 2 * PAGE_SIZE; \
359+
GLOBAL(name)
360+
#else
361+
#define NEXT_PGD_PAGE(name) NEXT_PAGE(name)
362+
#define PTI_USER_PGD_FILL 0
363+
#endif
364+
344365
/* Automate the creation of 1 to 1 mapping pmd entries */
345366
#define PMDS(START, PERM, COUNT) \
346367
i = 0 ; \
@@ -350,27 +371,29 @@ GLOBAL(name)
350371
.endr
351372

352373
__INITDATA
353-
NEXT_PAGE(early_top_pgt)
374+
NEXT_PGD_PAGE(early_top_pgt)
354375
.fill 511,8,0
355376
#ifdef CONFIG_X86_5LEVEL
356377
.quad level4_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
357378
#else
358379
.quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
359380
#endif
381+
.fill PTI_USER_PGD_FILL,8,0
360382

361383
NEXT_PAGE(early_dynamic_pgts)
362384
.fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0
363385

364386
.data
365387

366388
#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH)
367-
NEXT_PAGE(init_top_pgt)
389+
NEXT_PGD_PAGE(init_top_pgt)
368390
.quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
369391
.org init_top_pgt + PGD_PAGE_OFFSET*8, 0
370392
.quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
371393
.org init_top_pgt + PGD_START_KERNEL*8, 0
372394
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
373395
.quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
396+
.fill PTI_USER_PGD_FILL,8,0
374397

375398
NEXT_PAGE(level3_ident_pgt)
376399
.quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
@@ -381,8 +404,9 @@ NEXT_PAGE(level2_ident_pgt)
381404
*/
382405
PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
383406
#else
384-
NEXT_PAGE(init_top_pgt)
407+
NEXT_PGD_PAGE(init_top_pgt)
385408
.fill 512,8,0
409+
.fill PTI_USER_PGD_FILL,8,0
386410
#endif
387411

388412
#ifdef CONFIG_X86_5LEVEL

arch/x86/mm/pgtable.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,15 @@ static inline void _pgd_free(pgd_t *pgd)
355355
kmem_cache_free(pgd_cache, pgd);
356356
}
357357
#else
358+
358359
static inline pgd_t *_pgd_alloc(void)
359360
{
360-
return (pgd_t *)__get_free_page(PGALLOC_GFP);
361+
return (pgd_t *)__get_free_pages(PGALLOC_GFP, PGD_ALLOCATION_ORDER);
361362
}
362363

363364
static inline void _pgd_free(pgd_t *pgd)
364365
{
365-
free_page((unsigned long)pgd);
366+
free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER);
366367
}
367368
#endif /* CONFIG_X86_PAE */
368369

arch/x86/platform/efi/efi_64.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ static pgd_t *efi_pgd;
195195
* because we want to avoid inserting EFI region mappings (EFI_VA_END
196196
* to EFI_VA_START) into the standard kernel page tables. Everything
197197
* else can be shared, see efi_sync_low_kernel_mappings().
198+
*
199+
* We don't want the pgd on the pgd_list and cannot use pgd_alloc() for the
200+
* allocation.
198201
*/
199202
int __init efi_alloc_page_tables(void)
200203
{
@@ -207,7 +210,7 @@ int __init efi_alloc_page_tables(void)
207210
return 0;
208211

209212
gfp_mask = GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO;
210-
efi_pgd = (pgd_t *)__get_free_page(gfp_mask);
213+
efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER);
211214
if (!efi_pgd)
212215
return -ENOMEM;
213216

0 commit comments

Comments
 (0)