Commit c9c98bc5 authored by Oliver O'Halloran's avatar Oliver O'Halloran Committed by Michael Ellerman

powerpc/mm: Fix pmd/pte_devmap() on non-leaf entries

The Radix MMU translation tree as defined in ISA v3.0 contains two
different types of entry, directories and leaves. Leaves are
identified by _PAGE_PTE being set.

The formats of the two entries are different, with the directory
entries containing no spare bits for use by software. In particular
the bit we use for _PAGE_DEVMAP is not reserved for software, and is
part of the NLB (Next Level Base) field, essentially the address of
the next level in the tree.

Note that the Linux pte_t is not == _PAGE_PTE. A huge page pmd
entry (or devmap!) is also a leaf and so has _PAGE_PTE set, even
though we use a pmd_t for it in Linux.

The fix is to ensure that the pmd/pte_devmap() confirm they are
looking at a leaf entry (_PAGE_PTE) as well as checking _PAGE_DEVMAP.

Fixes: ebd31197 ("powerpc/mm: Add devmap support for ppc64")
Signed-off-by: default avatarOliver O'Halloran <oohall@gmail.com>
Tested-by: default avatarLaurent Vivier <lvivier@redhat.com>
Tested-by: default avatarJose Ricardo Ziviani <joserz@linux.vnet.ibm.com>
Reviewed-by: default avatarSuraj Jitindar Singh <sjitindarsingh@gmail.com>
Reviewed-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
[mpe: Add a comment in the code and flesh out change log]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 0da12a7a
...@@ -608,9 +608,17 @@ static inline pte_t pte_mkdevmap(pte_t pte) ...@@ -608,9 +608,17 @@ static inline pte_t pte_mkdevmap(pte_t pte)
return __pte(pte_val(pte) | _PAGE_SPECIAL|_PAGE_DEVMAP); return __pte(pte_val(pte) | _PAGE_SPECIAL|_PAGE_DEVMAP);
} }
/*
* This is potentially called with a pmd as the argument, in which case it's not
* safe to check _PAGE_DEVMAP unless we also confirm that _PAGE_PTE is set.
* That's because the bit we use for _PAGE_DEVMAP is not reserved for software
* use in page directory entries (ie. non-ptes).
*/
static inline int pte_devmap(pte_t pte) static inline int pte_devmap(pte_t pte)
{ {
return !!(pte_raw(pte) & cpu_to_be64(_PAGE_DEVMAP)); u64 mask = cpu_to_be64(_PAGE_DEVMAP | _PAGE_PTE);
return (pte_raw(pte) & mask) == mask;
} }
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
......
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