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); |
