aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r--arch/arm/kernel/traps.c47
1 files changed, 29 insertions, 18 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f6de76e0a45d..45e9ea6cd2a5 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -198,25 +198,16 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
198 barrier(); 198 barrier();
199} 199}
200 200
201DEFINE_SPINLOCK(die_lock); 201static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
202
203/*
204 * This function is protected against re-entrancy.
205 */
206NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
207{ 202{
208 struct task_struct *tsk = current; 203 struct task_struct *tsk = thread->task;
209 static int die_counter; 204 static int die_counter;
210 205
211 console_verbose();
212 spin_lock_irq(&die_lock);
213 bust_spinlocks(1);
214
215 printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter); 206 printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);
216 print_modules(); 207 print_modules();
217 __show_regs(regs); 208 __show_regs(regs);
218 printk("Process %s (pid: %d, stack limit = 0x%p)\n", 209 printk("Process %s (pid: %d, stack limit = 0x%p)\n",
219 tsk->comm, tsk->pid, tsk->thread_info + 1); 210 tsk->comm, tsk->pid, thread + 1);
220 211
221 if (!user_mode(regs) || in_interrupt()) { 212 if (!user_mode(regs) || in_interrupt()) {
222 dump_mem("Stack: ", regs->ARM_sp, 213 dump_mem("Stack: ", regs->ARM_sp,
@@ -224,7 +215,21 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
224 dump_backtrace(regs, tsk); 215 dump_backtrace(regs, tsk);
225 dump_instr(regs); 216 dump_instr(regs);
226 } 217 }
218}
219
220DEFINE_SPINLOCK(die_lock);
221
222/*
223 * This function is protected against re-entrancy.
224 */
225NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
226{
227 struct thread_info *thread = current_thread_info();
227 228
229 console_verbose();
230 spin_lock_irq(&die_lock);
231 bust_spinlocks(1);
232 __die(str, err, thread, regs);
228 bust_spinlocks(0); 233 bust_spinlocks(0);
229 spin_unlock_irq(&die_lock); 234 spin_unlock_irq(&die_lock);
230 do_exit(SIGSEGV); 235 do_exit(SIGSEGV);
@@ -345,7 +350,9 @@ static int bad_syscall(int n, struct pt_regs *regs)
345 struct thread_info *thread = current_thread_info(); 350 struct thread_info *thread = current_thread_info();
346 siginfo_t info; 351 siginfo_t info;
347 352
348 if (current->personality != PER_LINUX && thread->exec_domain->handler) { 353 if (current->personality != PER_LINUX &&
354 current->personality != PER_LINUX_32BIT &&
355 thread->exec_domain->handler) {
349 thread->exec_domain->handler(n, regs); 356 thread->exec_domain->handler(n, regs);
350 return regs->ARM_r0; 357 return regs->ARM_r0;
351 } 358 }
@@ -481,29 +488,33 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
481 unsigned long addr = regs->ARM_r2; 488 unsigned long addr = regs->ARM_r2;
482 struct mm_struct *mm = current->mm; 489 struct mm_struct *mm = current->mm;
483 pgd_t *pgd; pmd_t *pmd; pte_t *pte; 490 pgd_t *pgd; pmd_t *pmd; pte_t *pte;
491 spinlock_t *ptl;
484 492
485 regs->ARM_cpsr &= ~PSR_C_BIT; 493 regs->ARM_cpsr &= ~PSR_C_BIT;
486 spin_lock(&mm->page_table_lock); 494 down_read(&mm->mmap_sem);
487 pgd = pgd_offset(mm, addr); 495 pgd = pgd_offset(mm, addr);
488 if (!pgd_present(*pgd)) 496 if (!pgd_present(*pgd))
489 goto bad_access; 497 goto bad_access;
490 pmd = pmd_offset(pgd, addr); 498 pmd = pmd_offset(pgd, addr);
491 if (!pmd_present(*pmd)) 499 if (!pmd_present(*pmd))
492 goto bad_access; 500 goto bad_access;
493 pte = pte_offset_map(pmd, addr); 501 pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
494 if (!pte_present(*pte) || !pte_write(*pte)) 502 if (!pte_present(*pte) || !pte_write(*pte)) {
503 pte_unmap_unlock(pte, ptl);
495 goto bad_access; 504 goto bad_access;
505 }
496 val = *(unsigned long *)addr; 506 val = *(unsigned long *)addr;
497 val -= regs->ARM_r0; 507 val -= regs->ARM_r0;
498 if (val == 0) { 508 if (val == 0) {
499 *(unsigned long *)addr = regs->ARM_r1; 509 *(unsigned long *)addr = regs->ARM_r1;
500 regs->ARM_cpsr |= PSR_C_BIT; 510 regs->ARM_cpsr |= PSR_C_BIT;
501 } 511 }
502 spin_unlock(&mm->page_table_lock); 512 pte_unmap_unlock(pte, ptl);
513 up_read(&mm->mmap_sem);
503 return val; 514 return val;
504 515
505 bad_access: 516 bad_access:
506 spin_unlock(&mm->page_table_lock); 517 up_read(&mm->mmap_sem);
507 /* simulate a write access fault */ 518 /* simulate a write access fault */
508 do_DataAbort(addr, 15 + (1 << 11), regs); 519 do_DataAbort(addr, 15 + (1 << 11), regs);
509 return -1; 520 return -1;