diff options
Diffstat (limited to 'arch/mips/mm/fault.c')
-rw-r--r-- | arch/mips/mm/fault.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index ec8077c74e9c..2d9624fd10ec 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/system.h> | 25 | #include <asm/system.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | #include <asm/ptrace.h> | 27 | #include <asm/ptrace.h> |
28 | #include <asm/highmem.h> /* For VMALLOC_END */ | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * This routine handles page faults. It determines the address, | 31 | * This routine handles page faults. It determines the address, |
@@ -57,7 +58,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, | |||
57 | * only copy the information from the master page table, | 58 | * only copy the information from the master page table, |
58 | * nothing more. | 59 | * nothing more. |
59 | */ | 60 | */ |
60 | if (unlikely(address >= VMALLOC_START)) | 61 | if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) |
61 | goto vmalloc_fault; | 62 | goto vmalloc_fault; |
62 | 63 | ||
63 | /* | 64 | /* |
@@ -140,7 +141,7 @@ bad_area_nosemaphore: | |||
140 | info.si_signo = SIGSEGV; | 141 | info.si_signo = SIGSEGV; |
141 | info.si_errno = 0; | 142 | info.si_errno = 0; |
142 | /* info.si_code has been set above */ | 143 | /* info.si_code has been set above */ |
143 | info.si_addr = (void *) address; | 144 | info.si_addr = (void __user *) address; |
144 | force_sig_info(SIGSEGV, &info, tsk); | 145 | force_sig_info(SIGSEGV, &info, tsk); |
145 | return; | 146 | return; |
146 | } | 147 | } |
@@ -196,7 +197,7 @@ do_sigbus: | |||
196 | info.si_signo = SIGBUS; | 197 | info.si_signo = SIGBUS; |
197 | info.si_errno = 0; | 198 | info.si_errno = 0; |
198 | info.si_code = BUS_ADRERR; | 199 | info.si_code = BUS_ADRERR; |
199 | info.si_addr = (void *) address; | 200 | info.si_addr = (void __user *) address; |
200 | force_sig_info(SIGBUS, &info, tsk); | 201 | force_sig_info(SIGBUS, &info, tsk); |
201 | 202 | ||
202 | return; | 203 | return; |
@@ -212,6 +213,7 @@ vmalloc_fault: | |||
212 | */ | 213 | */ |
213 | int offset = __pgd_offset(address); | 214 | int offset = __pgd_offset(address); |
214 | pgd_t *pgd, *pgd_k; | 215 | pgd_t *pgd, *pgd_k; |
216 | pud_t *pud, *pud_k; | ||
215 | pmd_t *pmd, *pmd_k; | 217 | pmd_t *pmd, *pmd_k; |
216 | pte_t *pte_k; | 218 | pte_t *pte_k; |
217 | 219 | ||
@@ -222,8 +224,13 @@ vmalloc_fault: | |||
222 | goto no_context; | 224 | goto no_context; |
223 | set_pgd(pgd, *pgd_k); | 225 | set_pgd(pgd, *pgd_k); |
224 | 226 | ||
225 | pmd = pmd_offset(pgd, address); | 227 | pud = pud_offset(pgd, address); |
226 | pmd_k = pmd_offset(pgd_k, address); | 228 | pud_k = pud_offset(pgd_k, address); |
229 | if (!pud_present(*pud_k)) | ||
230 | goto no_context; | ||
231 | |||
232 | pmd = pmd_offset(pud, address); | ||
233 | pmd_k = pmd_offset(pud_k, address); | ||
227 | if (!pmd_present(*pmd_k)) | 234 | if (!pmd_present(*pmd_k)) |
228 | goto no_context; | 235 | goto no_context; |
229 | set_pmd(pmd, *pmd_k); | 236 | set_pmd(pmd, *pmd_k); |