diff options
| -rw-r--r-- | arch/parisc/include/asm/uaccess.h | 2 | ||||
| -rw-r--r-- | arch/parisc/kernel/traps.c | 4 | ||||
| -rw-r--r-- | arch/parisc/mm/fault.c | 58 |
3 files changed, 37 insertions, 27 deletions
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 4878b9501f24..1c6dbb6f6e56 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h | |||
| @@ -241,4 +241,6 @@ unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned lo | |||
| 241 | #define __copy_to_user_inatomic __copy_to_user | 241 | #define __copy_to_user_inatomic __copy_to_user |
| 242 | #define __copy_from_user_inatomic __copy_from_user | 242 | #define __copy_from_user_inatomic __copy_from_user |
| 243 | 243 | ||
| 244 | int fixup_exception(struct pt_regs *regs); | ||
| 245 | |||
| 244 | #endif /* __PARISC_UACCESS_H */ | 246 | #endif /* __PARISC_UACCESS_H */ |
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 4c771cd580ec..548ba0c654d2 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c | |||
| @@ -745,6 +745,10 @@ void handle_interruption(int code, struct pt_regs *regs) | |||
| 745 | /* Fall Through */ | 745 | /* Fall Through */ |
| 746 | case 27: | 746 | case 27: |
| 747 | /* Data memory protection ID trap */ | 747 | /* Data memory protection ID trap */ |
| 748 | if (code == 27 && !user_mode(regs) && | ||
| 749 | fixup_exception(regs)) | ||
| 750 | return; | ||
| 751 | |||
| 748 | die_if_kernel("Protection id trap", regs, code); | 752 | die_if_kernel("Protection id trap", regs, code); |
| 749 | si.si_code = SEGV_MAPERR; | 753 | si.si_code = SEGV_MAPERR; |
| 750 | si.si_signo = SIGSEGV; | 754 | si.si_signo = SIGSEGV; |
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index b2e3e9a8cece..92c7fa4ecc3f 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c | |||
| @@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst) | |||
| 139 | } | 139 | } |
| 140 | #endif | 140 | #endif |
| 141 | 141 | ||
| 142 | int fixup_exception(struct pt_regs *regs) | ||
| 143 | { | ||
| 144 | const struct exception_table_entry *fix; | ||
| 145 | |||
| 146 | fix = search_exception_tables(regs->iaoq[0]); | ||
| 147 | if (fix) { | ||
| 148 | struct exception_data *d; | ||
| 149 | d = &__get_cpu_var(exception_data); | ||
| 150 | d->fault_ip = regs->iaoq[0]; | ||
| 151 | d->fault_space = regs->isr; | ||
| 152 | d->fault_addr = regs->ior; | ||
| 153 | |||
| 154 | regs->iaoq[0] = ((fix->fixup) & ~3); | ||
| 155 | /* | ||
| 156 | * NOTE: In some cases the faulting instruction | ||
| 157 | * may be in the delay slot of a branch. We | ||
| 158 | * don't want to take the branch, so we don't | ||
| 159 | * increment iaoq[1], instead we set it to be | ||
| 160 | * iaoq[0]+4, and clear the B bit in the PSW | ||
| 161 | */ | ||
| 162 | regs->iaoq[1] = regs->iaoq[0] + 4; | ||
| 163 | regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */ | ||
| 164 | |||
| 165 | return 1; | ||
| 166 | } | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 142 | void do_page_fault(struct pt_regs *regs, unsigned long code, | 171 | void do_page_fault(struct pt_regs *regs, unsigned long code, |
| 143 | unsigned long address) | 172 | unsigned long address) |
| 144 | { | 173 | { |
| 145 | struct vm_area_struct *vma, *prev_vma; | 174 | struct vm_area_struct *vma, *prev_vma; |
| 146 | struct task_struct *tsk = current; | 175 | struct task_struct *tsk = current; |
| 147 | struct mm_struct *mm = tsk->mm; | 176 | struct mm_struct *mm = tsk->mm; |
| 148 | const struct exception_table_entry *fix; | ||
| 149 | unsigned long acc_type; | 177 | unsigned long acc_type; |
| 150 | int fault; | 178 | int fault; |
| 151 | 179 | ||
| @@ -229,32 +257,8 @@ bad_area: | |||
| 229 | 257 | ||
| 230 | no_context: | 258 | no_context: |
| 231 | 259 | ||
| 232 | if (!user_mode(regs)) { | 260 | if (!user_mode(regs) && fixup_exception(regs)) { |
| 233 | fix = search_exception_tables(regs->iaoq[0]); | 261 | return; |
| 234 | |||
| 235 | if (fix) { | ||
| 236 | struct exception_data *d; | ||
| 237 | |||
| 238 | d = &__get_cpu_var(exception_data); | ||
| 239 | d->fault_ip = regs->iaoq[0]; | ||
| 240 | d->fault_space = regs->isr; | ||
| 241 | d->fault_addr = regs->ior; | ||
| 242 | |||
| 243 | regs->iaoq[0] = ((fix->fixup) & ~3); | ||
| 244 | |||
| 245 | /* | ||
| 246 | * NOTE: In some cases the faulting instruction | ||
| 247 | * may be in the delay slot of a branch. We | ||
| 248 | * don't want to take the branch, so we don't | ||
| 249 | * increment iaoq[1], instead we set it to be | ||
| 250 | * iaoq[0]+4, and clear the B bit in the PSW | ||
| 251 | */ | ||
| 252 | |||
| 253 | regs->iaoq[1] = regs->iaoq[0] + 4; | ||
| 254 | regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */ | ||
| 255 | |||
| 256 | return; | ||
| 257 | } | ||
| 258 | } | 262 | } |
| 259 | 263 | ||
| 260 | parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); | 264 | parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); |
