Skip to content

Commit 9d1dcdf

Browse files
kirylbp3tk0v
authored andcommitted
x86/mm: Return correct level from lookup_address() if pte is none
Currently, lookup_address() returns two things: 1. A "pte_t" (which might be a p[g4um]d_t) 2. The 'level' of the page tables where the "pte_t" was found (returned via a pointer) If no pte_t is found, 'level' is essentially garbage. Always fill out the level. For NULL "pte_t"s, fill in the level where the p*d_none() entry was found mirroring the "found" behavior. Always filling out the level allows using lookup_address() to precisely skip over holes when walking kernel page tables. Add one more entry into enum pg_level to indicate the size of the VA covered by one PGD entry in 5-level paging mode. Update comments for lookup_address() and lookup_address_in_pgd() to reflect changes in the interface. Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Rick Edgecombe <[email protected]> Reviewed-by: Baoquan He <[email protected]> Reviewed-by: Dave Hansen <[email protected]> Tested-by: Tao Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 99c5c4c commit 9d1dcdf

File tree

2 files changed

+11
-11
lines changed

2 files changed

+11
-11
lines changed

arch/x86/include/asm/pgtable_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ enum pg_level {
549549
PG_LEVEL_2M,
550550
PG_LEVEL_1G,
551551
PG_LEVEL_512G,
552+
PG_LEVEL_256T,
552553
PG_LEVEL_NUM
553554
};
554555

arch/x86/mm/pat/set_memory.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,9 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star
662662

663663
/*
664664
* Lookup the page table entry for a virtual address in a specific pgd.
665-
* Return a pointer to the entry, the level of the mapping, and the effective
666-
* NX and RW bits of all page table levels.
665+
* Return a pointer to the entry (or NULL if the entry does not exist),
666+
* the level of the entry, and the effective NX and RW bits of all
667+
* page table levels.
667668
*/
668669
pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
669670
unsigned int *level, bool *nx, bool *rw)
@@ -672,51 +673,50 @@ pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address,
672673
pud_t *pud;
673674
pmd_t *pmd;
674675

675-
*level = PG_LEVEL_NONE;
676+
*level = PG_LEVEL_256T;
676677
*nx = false;
677678
*rw = true;
678679

679680
if (pgd_none(*pgd))
680681
return NULL;
681682

683+
*level = PG_LEVEL_512G;
682684
*nx |= pgd_flags(*pgd) & _PAGE_NX;
683685
*rw &= pgd_flags(*pgd) & _PAGE_RW;
684686

685687
p4d = p4d_offset(pgd, address);
686688
if (p4d_none(*p4d))
687689
return NULL;
688690

689-
*level = PG_LEVEL_512G;
690691
if (p4d_leaf(*p4d) || !p4d_present(*p4d))
691692
return (pte_t *)p4d;
692693

694+
*level = PG_LEVEL_1G;
693695
*nx |= p4d_flags(*p4d) & _PAGE_NX;
694696
*rw &= p4d_flags(*p4d) & _PAGE_RW;
695697

696698
pud = pud_offset(p4d, address);
697699
if (pud_none(*pud))
698700
return NULL;
699701

700-
*level = PG_LEVEL_1G;
701702
if (pud_leaf(*pud) || !pud_present(*pud))
702703
return (pte_t *)pud;
703704

705+
*level = PG_LEVEL_2M;
704706
*nx |= pud_flags(*pud) & _PAGE_NX;
705707
*rw &= pud_flags(*pud) & _PAGE_RW;
706708

707709
pmd = pmd_offset(pud, address);
708710
if (pmd_none(*pmd))
709711
return NULL;
710712

711-
*level = PG_LEVEL_2M;
712713
if (pmd_leaf(*pmd) || !pmd_present(*pmd))
713714
return (pte_t *)pmd;
714715

716+
*level = PG_LEVEL_4K;
715717
*nx |= pmd_flags(*pmd) & _PAGE_NX;
716718
*rw &= pmd_flags(*pmd) & _PAGE_RW;
717719

718-
*level = PG_LEVEL_4K;
719-
720720
return pte_offset_kernel(pmd, address);
721721
}
722722

@@ -736,9 +736,8 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
736736
* Lookup the page table entry for a virtual address. Return a pointer
737737
* to the entry and the level of the mapping.
738738
*
739-
* Note: We return pud and pmd either when the entry is marked large
740-
* or when the present bit is not set. Otherwise we would return a
741-
* pointer to a nonexisting mapping.
739+
* Note: the function returns p4d, pud or pmd either when the entry is marked
740+
* large or when the present bit is not set. Otherwise it returns NULL.
742741
*/
743742
pte_t *lookup_address(unsigned long address, unsigned int *level)
744743
{

0 commit comments

Comments
 (0)