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 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/ptrace.h> +#include <asm/highmem.h> /* For VMALLOC_END */ /* * 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, * only copy the information from the master page table, * nothing more. */ - if (unlikely(address >= VMALLOC_START)) + if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) goto vmalloc_fault; /* @@ -140,7 +141,7 @@ bad_area_nosemaphore: info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; force_sig_info(SIGSEGV, &info, tsk); return; } @@ -196,7 +197,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; force_sig_info(SIGBUS, &info, tsk); return; @@ -212,6 +213,7 @@ vmalloc_fault: */ int offset = __pgd_offset(address); pgd_t *pgd, *pgd_k; + pud_t *pud, *pud_k; pmd_t *pmd, *pmd_k; pte_t *pte_k; @@ -222,8 +224,13 @@ vmalloc_fault: goto no_context; set_pgd(pgd, *pgd_k); - pmd = pmd_offset(pgd, address); - pmd_k = pmd_offset(pgd_k, address); + pud = pud_offset(pgd, address); + pud_k = pud_offset(pgd_k, address); + if (!pud_present(*pud_k)) + goto no_context; + + pmd = pmd_offset(pud, address); + pmd_k = pmd_offset(pud_k, address); if (!pmd_present(*pmd_k)) goto no_context; set_pmd(pmd, *pmd_k); |