diff options
author | Harvey Harrison <harvey.harrison@gmail.com> | 2008-01-30 07:33:13 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:33:13 -0500 |
commit | fdfe8aa84dd78cfdff427d0520f5974fb5e9c220 (patch) | |
tree | 0d9ee510fa3bc5652e345bec5fb5ffd66010ca97 /arch/x86 | |
parent | 6f4d368ef9e9f91aa0019c11e90773ea32d94625 (diff) |
x86: function ifdefs in fault_32|64.c
Add caller of is_errata93() to X86_32, ifdef'd to do
nothing.
Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/mm/fault_32.c | 59 | ||||
-rw-r--r-- | arch/x86/mm/fault_64.c | 30 |
2 files changed, 83 insertions, 6 deletions
diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index 31113deeb7c0..eba90198b15a 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c | |||
@@ -217,6 +217,7 @@ KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n" | |||
217 | KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n" | 217 | KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n" |
218 | KERN_ERR "******* Please consider a BIOS update.\n" | 218 | KERN_ERR "******* Please consider a BIOS update.\n" |
219 | KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; | 219 | KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; |
220 | #endif | ||
220 | 221 | ||
221 | /* Workaround for K8 erratum #93 & buggy BIOS. | 222 | /* Workaround for K8 erratum #93 & buggy BIOS. |
222 | BIOS SMM functions are required to use a specific workaround | 223 | BIOS SMM functions are required to use a specific workaround |
@@ -224,10 +225,12 @@ KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; | |||
224 | A lot of BIOS that didn't get tested properly miss this. | 225 | A lot of BIOS that didn't get tested properly miss this. |
225 | The OS sees this as a page fault with the upper 32bits of RIP cleared. | 226 | The OS sees this as a page fault with the upper 32bits of RIP cleared. |
226 | Try to work around it here. | 227 | Try to work around it here. |
227 | Note we only handle faults in kernel here. */ | 228 | Note we only handle faults in kernel here. |
228 | 229 | Does nothing for X86_32 | |
230 | */ | ||
229 | static int is_errata93(struct pt_regs *regs, unsigned long address) | 231 | static int is_errata93(struct pt_regs *regs, unsigned long address) |
230 | { | 232 | { |
233 | #ifdef CONFIG_X86_64 | ||
231 | static int warned; | 234 | static int warned; |
232 | if (address != regs->ip) | 235 | if (address != regs->ip) |
233 | return 0; | 236 | return 0; |
@@ -243,9 +246,10 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) | |||
243 | regs->ip = address; | 246 | regs->ip = address; |
244 | return 1; | 247 | return 1; |
245 | } | 248 | } |
249 | #endif | ||
246 | return 0; | 250 | return 0; |
247 | } | 251 | } |
248 | #endif | 252 | |
249 | 253 | ||
250 | /* | 254 | /* |
251 | * Handle a fault on the vmalloc or module mapping area | 255 | * Handle a fault on the vmalloc or module mapping area |
@@ -254,6 +258,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) | |||
254 | */ | 258 | */ |
255 | static inline int vmalloc_fault(unsigned long address) | 259 | static inline int vmalloc_fault(unsigned long address) |
256 | { | 260 | { |
261 | #ifdef CONFIG_X86_32 | ||
257 | unsigned long pgd_paddr; | 262 | unsigned long pgd_paddr; |
258 | pmd_t *pmd_k; | 263 | pmd_t *pmd_k; |
259 | pte_t *pte_k; | 264 | pte_t *pte_k; |
@@ -272,6 +277,51 @@ static inline int vmalloc_fault(unsigned long address) | |||
272 | if (!pte_present(*pte_k)) | 277 | if (!pte_present(*pte_k)) |
273 | return -1; | 278 | return -1; |
274 | return 0; | 279 | return 0; |
280 | #else | ||
281 | pgd_t *pgd, *pgd_ref; | ||
282 | pud_t *pud, *pud_ref; | ||
283 | pmd_t *pmd, *pmd_ref; | ||
284 | pte_t *pte, *pte_ref; | ||
285 | |||
286 | /* Copy kernel mappings over when needed. This can also | ||
287 | happen within a race in page table update. In the later | ||
288 | case just flush. */ | ||
289 | |||
290 | pgd = pgd_offset(current->mm ?: &init_mm, address); | ||
291 | pgd_ref = pgd_offset_k(address); | ||
292 | if (pgd_none(*pgd_ref)) | ||
293 | return -1; | ||
294 | if (pgd_none(*pgd)) | ||
295 | set_pgd(pgd, *pgd_ref); | ||
296 | else | ||
297 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); | ||
298 | |||
299 | /* Below here mismatches are bugs because these lower tables | ||
300 | are shared */ | ||
301 | |||
302 | pud = pud_offset(pgd, address); | ||
303 | pud_ref = pud_offset(pgd_ref, address); | ||
304 | if (pud_none(*pud_ref)) | ||
305 | return -1; | ||
306 | if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref)) | ||
307 | BUG(); | ||
308 | pmd = pmd_offset(pud, address); | ||
309 | pmd_ref = pmd_offset(pud_ref, address); | ||
310 | if (pmd_none(*pmd_ref)) | ||
311 | return -1; | ||
312 | if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref)) | ||
313 | BUG(); | ||
314 | pte_ref = pte_offset_kernel(pmd_ref, address); | ||
315 | if (!pte_present(*pte_ref)) | ||
316 | return -1; | ||
317 | pte = pte_offset_kernel(pmd, address); | ||
318 | /* Don't use pte_page here, because the mappings can point | ||
319 | outside mem_map, and the NUMA hash lookup cannot handle | ||
320 | that. */ | ||
321 | if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref)) | ||
322 | BUG(); | ||
323 | return 0; | ||
324 | #endif | ||
275 | } | 325 | } |
276 | 326 | ||
277 | int show_unhandled_signals = 1; | 327 | int show_unhandled_signals = 1; |
@@ -507,6 +557,9 @@ no_context: | |||
507 | if (is_prefetch(regs, address, error_code)) | 557 | if (is_prefetch(regs, address, error_code)) |
508 | return; | 558 | return; |
509 | 559 | ||
560 | if (is_errata93(regs, address)) | ||
561 | return; | ||
562 | |||
510 | /* | 563 | /* |
511 | * Oops. The kernel tried to access some bad page. We'll have to | 564 | * Oops. The kernel tried to access some bad page. We'll have to |
512 | * terminate things with extreme prejudice. | 565 | * terminate things with extreme prejudice. |
diff --git a/arch/x86/mm/fault_64.c b/arch/x86/mm/fault_64.c index c48d95c306df..75b7b165bdf3 100644 --- a/arch/x86/mm/fault_64.c +++ b/arch/x86/mm/fault_64.c | |||
@@ -223,6 +223,7 @@ KERN_ERR "******* Your BIOS seems to not contain a fix for K8 errata #93\n" | |||
223 | KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n" | 223 | KERN_ERR "******* Working around it, but it may cause SEGVs or burn power.\n" |
224 | KERN_ERR "******* Please consider a BIOS update.\n" | 224 | KERN_ERR "******* Please consider a BIOS update.\n" |
225 | KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; | 225 | KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; |
226 | #endif | ||
226 | 227 | ||
227 | /* Workaround for K8 erratum #93 & buggy BIOS. | 228 | /* Workaround for K8 erratum #93 & buggy BIOS. |
228 | BIOS SMM functions are required to use a specific workaround | 229 | BIOS SMM functions are required to use a specific workaround |
@@ -230,10 +231,12 @@ KERN_ERR "******* Disabling USB legacy in the BIOS may also help.\n"; | |||
230 | A lot of BIOS that didn't get tested properly miss this. | 231 | A lot of BIOS that didn't get tested properly miss this. |
231 | The OS sees this as a page fault with the upper 32bits of RIP cleared. | 232 | The OS sees this as a page fault with the upper 32bits of RIP cleared. |
232 | Try to work around it here. | 233 | Try to work around it here. |
233 | Note we only handle faults in kernel here. */ | 234 | Note we only handle faults in kernel here. |
234 | 235 | Does nothing for X86_32 | |
236 | */ | ||
235 | static int is_errata93(struct pt_regs *regs, unsigned long address) | 237 | static int is_errata93(struct pt_regs *regs, unsigned long address) |
236 | { | 238 | { |
239 | #ifdef CONFIG_X86_64 | ||
237 | static int warned; | 240 | static int warned; |
238 | if (address != regs->ip) | 241 | if (address != regs->ip) |
239 | return 0; | 242 | return 0; |
@@ -249,9 +252,9 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) | |||
249 | regs->ip = address; | 252 | regs->ip = address; |
250 | return 1; | 253 | return 1; |
251 | } | 254 | } |
255 | #endif | ||
252 | return 0; | 256 | return 0; |
253 | } | 257 | } |
254 | #endif | ||
255 | 258 | ||
256 | static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | 259 | static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, |
257 | unsigned long error_code) | 260 | unsigned long error_code) |
@@ -278,6 +281,26 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
278 | */ | 281 | */ |
279 | static int vmalloc_fault(unsigned long address) | 282 | static int vmalloc_fault(unsigned long address) |
280 | { | 283 | { |
284 | #ifdef CONFIG_X86_32 | ||
285 | unsigned long pgd_paddr; | ||
286 | pmd_t *pmd_k; | ||
287 | pte_t *pte_k; | ||
288 | /* | ||
289 | * Synchronize this task's top level page-table | ||
290 | * with the 'reference' page table. | ||
291 | * | ||
292 | * Do _not_ use "current" here. We might be inside | ||
293 | * an interrupt in the middle of a task switch.. | ||
294 | */ | ||
295 | pgd_paddr = read_cr3(); | ||
296 | pmd_k = vmalloc_sync_one(__va(pgd_paddr), address); | ||
297 | if (!pmd_k) | ||
298 | return -1; | ||
299 | pte_k = pte_offset_kernel(pmd_k, address); | ||
300 | if (!pte_present(*pte_k)) | ||
301 | return -1; | ||
302 | return 0; | ||
303 | #else | ||
281 | pgd_t *pgd, *pgd_ref; | 304 | pgd_t *pgd, *pgd_ref; |
282 | pud_t *pud, *pud_ref; | 305 | pud_t *pud, *pud_ref; |
283 | pmd_t *pmd, *pmd_ref; | 306 | pmd_t *pmd, *pmd_ref; |
@@ -321,6 +344,7 @@ static int vmalloc_fault(unsigned long address) | |||
321 | if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref)) | 344 | if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref)) |
322 | BUG(); | 345 | BUG(); |
323 | return 0; | 346 | return 0; |
347 | #endif | ||
324 | } | 348 | } |
325 | 349 | ||
326 | int show_unhandled_signals = 1; | 350 | int show_unhandled_signals = 1; |