diff options
-rw-r--r-- | arch/x86/kernel/mmiotrace/kmmio.c | 46 | ||||
-rw-r--r-- | arch/x86/kernel/mmiotrace/mmio-mod.c | 19 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 1 |
3 files changed, 44 insertions, 22 deletions
diff --git a/arch/x86/kernel/mmiotrace/kmmio.c b/arch/x86/kernel/mmiotrace/kmmio.c index 8ba48f9c91b4..28411dadb8b3 100644 --- a/arch/x86/kernel/mmiotrace/kmmio.c +++ b/arch/x86/kernel/mmiotrace/kmmio.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <asm/errno.h> | 21 | #include <asm/errno.h> |
22 | #include <asm/tlbflush.h> | 22 | #include <asm/tlbflush.h> |
23 | #include <asm/pgtable.h> | ||
23 | 24 | ||
24 | #include "kmmio.h" | 25 | #include "kmmio.h" |
25 | 26 | ||
@@ -117,40 +118,55 @@ static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page) | |||
117 | return NULL; | 118 | return NULL; |
118 | } | 119 | } |
119 | 120 | ||
120 | static void arm_kmmio_fault_page(unsigned long page, int *large) | 121 | static void arm_kmmio_fault_page(unsigned long page, int *page_level) |
121 | { | 122 | { |
122 | unsigned long address = page & PAGE_MASK; | 123 | unsigned long address = page & PAGE_MASK; |
123 | pgd_t *pgd = pgd_offset_k(address); | 124 | int level; |
124 | pud_t *pud = pud_offset(pgd, address); | 125 | pte_t *pte = lookup_address(address, &level); |
125 | pmd_t *pmd = pmd_offset(pud, address); | ||
126 | pte_t *pte = pte_offset_kernel(pmd, address); | ||
127 | 126 | ||
128 | if (pmd_large(*pmd)) { | 127 | if (!pte) { |
128 | printk(KERN_ERR "Error in %s: no pte for page 0x%08lx\n", | ||
129 | __FUNCTION__, page); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | if (level == PG_LEVEL_2M) { | ||
134 | pmd_t *pmd = (pmd_t *)pte; | ||
129 | set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_PRESENT)); | 135 | set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_PRESENT)); |
130 | if (large) | ||
131 | *large = 1; | ||
132 | } else { | 136 | } else { |
137 | /* PG_LEVEL_4K */ | ||
133 | set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); | 138 | set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); |
134 | } | 139 | } |
135 | 140 | ||
141 | if (page_level) | ||
142 | *page_level = level; | ||
143 | |||
136 | __flush_tlb_one(page); | 144 | __flush_tlb_one(page); |
137 | } | 145 | } |
138 | 146 | ||
139 | static void disarm_kmmio_fault_page(unsigned long page, int *large) | 147 | static void disarm_kmmio_fault_page(unsigned long page, int *page_level) |
140 | { | 148 | { |
141 | unsigned long address = page & PAGE_MASK; | 149 | unsigned long address = page & PAGE_MASK; |
142 | pgd_t *pgd = pgd_offset_k(address); | 150 | int level; |
143 | pud_t *pud = pud_offset(pgd, address); | 151 | pte_t *pte = lookup_address(address, &level); |
144 | pmd_t *pmd = pmd_offset(pud, address); | ||
145 | pte_t *pte = pte_offset_kernel(pmd, address); | ||
146 | 152 | ||
147 | if (large && *large) { | 153 | if (!pte) { |
154 | printk(KERN_ERR "Error in %s: no pte for page 0x%08lx\n", | ||
155 | __FUNCTION__, page); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | if (level == PG_LEVEL_2M) { | ||
160 | pmd_t *pmd = (pmd_t *)pte; | ||
148 | set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_PRESENT)); | 161 | set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_PRESENT)); |
149 | *large = 0; | ||
150 | } else { | 162 | } else { |
163 | /* PG_LEVEL_4K */ | ||
151 | set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); | 164 | set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); |
152 | } | 165 | } |
153 | 166 | ||
167 | if (page_level) | ||
168 | *page_level = level; | ||
169 | |||
154 | __flush_tlb_one(page); | 170 | __flush_tlb_one(page); |
155 | } | 171 | } |
156 | 172 | ||
diff --git a/arch/x86/kernel/mmiotrace/mmio-mod.c b/arch/x86/kernel/mmiotrace/mmio-mod.c index 73561fe85f03..e43947d218a5 100644 --- a/arch/x86/kernel/mmiotrace/mmio-mod.c +++ b/arch/x86/kernel/mmiotrace/mmio-mod.c | |||
@@ -120,19 +120,24 @@ static int write_marker(struct file *file, const char __user *buffer, | |||
120 | 120 | ||
121 | static void print_pte(unsigned long address) | 121 | static void print_pte(unsigned long address) |
122 | { | 122 | { |
123 | pgd_t *pgd = pgd_offset_k(address); | 123 | int level; |
124 | pud_t *pud = pud_offset(pgd, address); | 124 | pte_t *pte = lookup_address(address, &level); |
125 | pmd_t *pmd = pmd_offset(pud, address); | 125 | |
126 | if (pmd_large(*pmd)) { | 126 | if (!pte) { |
127 | printk(KERN_ERR "Error in %s: no pte for page 0x%08lx\n", | ||
128 | __FUNCTION__, address); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | if (level == PG_LEVEL_2M) { | ||
127 | printk(KERN_EMERG MODULE_NAME ": 4MB pages are not " | 133 | printk(KERN_EMERG MODULE_NAME ": 4MB pages are not " |
128 | "currently supported: %lx\n", | 134 | "currently supported: %lx\n", |
129 | address); | 135 | address); |
130 | BUG(); | 136 | BUG(); |
131 | } | 137 | } |
132 | printk(KERN_DEBUG MODULE_NAME ": pte for 0x%lx: 0x%lx 0x%lx\n", | 138 | printk(KERN_DEBUG MODULE_NAME ": pte for 0x%lx: 0x%lx 0x%lx\n", |
133 | address, | 139 | address, pte_val(*pte), |
134 | pte_val(*pte_offset_kernel(pmd, address)), | 140 | pte_val(*pte) & _PAGE_PRESENT); |
135 | pte_val(*pte_offset_kernel(pmd, address)) & _PAGE_PRESENT); | ||
136 | } | 141 | } |
137 | 142 | ||
138 | /* | 143 | /* |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 60bcb5b6a37e..57970f2935c0 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -227,6 +227,7 @@ pte_t *lookup_address(unsigned long address, unsigned int *level) | |||
227 | 227 | ||
228 | return pte_offset_kernel(pmd, address); | 228 | return pte_offset_kernel(pmd, address); |
229 | } | 229 | } |
230 | EXPORT_SYMBOL_GPL(lookup_address); | ||
230 | 231 | ||
231 | /* | 232 | /* |
232 | * Set the new pmd in all the pgds we know about: | 233 | * Set the new pmd in all the pgds we know about: |