diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-04 10:48:07 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-02-04 10:48:07 -0500 |
commit | 9a14aefc1d28c6037122965ee8c10d92a970ade0 (patch) | |
tree | 8f1342c4f18d075009abc9e4f05a6d4e4ba97640 | |
parent | 34508f66b69ff1708192654f631eb8f1d4c52005 (diff) |
x86: cpa, fix lookup_address
lookup_address() returns a wrong level and a wrong pointer to a non
existing pte, when pmd or pud entries are marked !present. This
happens for example due to boot time mapping of GART into the low
memory space.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/mm/pageattr.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 3810f7a83b1d..7d21cd658ed3 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -188,6 +188,14 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) | |||
188 | return prot; | 188 | return prot; |
189 | } | 189 | } |
190 | 190 | ||
191 | /* | ||
192 | * Lookup the page table entry for a virtual address. Return a pointer | ||
193 | * to the entry and the level of the mapping. | ||
194 | * | ||
195 | * Note: We return pud and pmd either when the entry is marked large | ||
196 | * or when the present bit is not set. Otherwise we would return a | ||
197 | * pointer to a nonexisting mapping. | ||
198 | */ | ||
191 | pte_t *lookup_address(unsigned long address, int *level) | 199 | pte_t *lookup_address(unsigned long address, int *level) |
192 | { | 200 | { |
193 | pgd_t *pgd = pgd_offset_k(address); | 201 | pgd_t *pgd = pgd_offset_k(address); |
@@ -206,7 +214,7 @@ pte_t *lookup_address(unsigned long address, int *level) | |||
206 | return NULL; | 214 | return NULL; |
207 | 215 | ||
208 | *level = PG_LEVEL_2M; | 216 | *level = PG_LEVEL_2M; |
209 | if (pmd_large(*pmd)) | 217 | if (pmd_large(*pmd) || !pmd_present(*pmd)) |
210 | return (pte_t *)pmd; | 218 | return (pte_t *)pmd; |
211 | 219 | ||
212 | *level = PG_LEVEL_4K; | 220 | *level = PG_LEVEL_4K; |