aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2014-04-06 18:04:12 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-05-09 10:47:47 -0400
commit9141300a5884b57cea6d32c4e3fd16a337cfc99a (patch)
treed717d0ae66c7458c922b885c689b9c192b0f4083
parent6400111399e16a535231ebd76389c894ea1837ff (diff)
arm64: Provide read/write fault information in compat signal handlers
For AArch32, bit 11 (WnR) of the FSR/ESR register is set when the fault was caused by a write access and applications like Qemu rely on such information being provided in sigcontext. This patch introduces the ESR_EL1 tracking for the arm64 kernel faults and sets bit 11 accordingly in compat sigcontext. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/include/asm/esr.h6
-rw-r--r--arch/arm64/include/asm/processor.h1
-rw-r--r--arch/arm64/kernel/signal32.c7
-rw-r--r--arch/arm64/kernel/traps.c7
-rw-r--r--arch/arm64/mm/fault.c8
5 files changed, 20 insertions, 9 deletions
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index c4a7f940b387..72674f4c3871 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -18,9 +18,11 @@
18#ifndef __ASM_ESR_H 18#ifndef __ASM_ESR_H
19#define __ASM_ESR_H 19#define __ASM_ESR_H
20 20
21#define ESR_EL1_EC_SHIFT (26) 21#define ESR_EL1_WRITE (1 << 6)
22#define ESR_EL1_IL (1U << 25) 22#define ESR_EL1_CM (1 << 8)
23#define ESR_EL1_IL (1 << 25)
23 24
25#define ESR_EL1_EC_SHIFT (26)
24#define ESR_EL1_EC_UNKNOWN (0x00) 26#define ESR_EL1_EC_UNKNOWN (0x00)
25#define ESR_EL1_EC_WFI (0x01) 27#define ESR_EL1_EC_WFI (0x01)
26#define ESR_EL1_EC_CP15_32 (0x03) 28#define ESR_EL1_EC_CP15_32 (0x03)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 45b20cd6cbca..34de2a8f7d93 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -79,6 +79,7 @@ struct thread_struct {
79 unsigned long tp_value; 79 unsigned long tp_value;
80 struct fpsimd_state fpsimd_state; 80 struct fpsimd_state fpsimd_state;
81 unsigned long fault_address; /* fault info */ 81 unsigned long fault_address; /* fault info */
82 unsigned long fault_code; /* ESR_EL1 value */
82 struct debug_info debug; /* debugging */ 83 struct debug_info debug; /* debugging */
83}; 84};
84 85
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index b3fc9f5ec6d3..050c1c2af777 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -23,6 +23,7 @@
23#include <linux/syscalls.h> 23#include <linux/syscalls.h>
24#include <linux/ratelimit.h> 24#include <linux/ratelimit.h>
25 25
26#include <asm/esr.h>
26#include <asm/fpsimd.h> 27#include <asm/fpsimd.h>
27#include <asm/signal32.h> 28#include <asm/signal32.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
@@ -81,6 +82,8 @@ struct compat_vfp_sigframe {
81#define VFP_MAGIC 0x56465001 82#define VFP_MAGIC 0x56465001
82#define VFP_STORAGE_SIZE sizeof(struct compat_vfp_sigframe) 83#define VFP_STORAGE_SIZE sizeof(struct compat_vfp_sigframe)
83 84
85#define FSR_WRITE_SHIFT (11)
86
84struct compat_aux_sigframe { 87struct compat_aux_sigframe {
85 struct compat_vfp_sigframe vfp; 88 struct compat_vfp_sigframe vfp;
86 89
@@ -500,7 +503,9 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,
500 __put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err); 503 __put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
501 504
502 __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err); 505 __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err);
503 __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.error_code, err); 506 /* set the compat FSR WnR */
507 __put_user_error(!!(current->thread.fault_code & ESR_EL1_WRITE) <<
508 FSR_WRITE_SHIFT, &sf->uc.uc_mcontext.error_code, err);
504 __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err); 509 __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
505 __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); 510 __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
506 511
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 7ffadddb645d..c43cfa9b8304 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -251,10 +251,13 @@ void die(const char *str, struct pt_regs *regs, int err)
251void arm64_notify_die(const char *str, struct pt_regs *regs, 251void arm64_notify_die(const char *str, struct pt_regs *regs,
252 struct siginfo *info, int err) 252 struct siginfo *info, int err)
253{ 253{
254 if (user_mode(regs)) 254 if (user_mode(regs)) {
255 current->thread.fault_address = 0;
256 current->thread.fault_code = err;
255 force_sig_info(info->si_signo, info, current); 257 force_sig_info(info->si_signo, info, current);
256 else 258 } else {
257 die(str, regs, err); 259 die(str, regs, err);
260 }
258} 261}
259 262
260asmlinkage void __exception do_undefinstr(struct pt_regs *regs) 263asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index c23751b06120..bcc965e2cce1 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -32,6 +32,7 @@
32 32
33#include <asm/exception.h> 33#include <asm/exception.h>
34#include <asm/debug-monitors.h> 34#include <asm/debug-monitors.h>
35#include <asm/esr.h>
35#include <asm/system_misc.h> 36#include <asm/system_misc.h>
36#include <asm/pgtable.h> 37#include <asm/pgtable.h>
37#include <asm/tlbflush.h> 38#include <asm/tlbflush.h>
@@ -123,6 +124,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
123 } 124 }
124 125
125 tsk->thread.fault_address = addr; 126 tsk->thread.fault_address = addr;
127 tsk->thread.fault_code = esr;
126 si.si_signo = sig; 128 si.si_signo = sig;
127 si.si_errno = 0; 129 si.si_errno = 0;
128 si.si_code = code; 130 si.si_code = code;
@@ -148,8 +150,6 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
148#define VM_FAULT_BADMAP 0x010000 150#define VM_FAULT_BADMAP 0x010000
149#define VM_FAULT_BADACCESS 0x020000 151#define VM_FAULT_BADACCESS 0x020000
150 152
151#define ESR_WRITE (1 << 6)
152#define ESR_CM (1 << 8)
153#define ESR_LNX_EXEC (1 << 24) 153#define ESR_LNX_EXEC (1 << 24)
154 154
155static int __do_page_fault(struct mm_struct *mm, unsigned long addr, 155static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
@@ -218,7 +218,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
218 218
219 if (esr & ESR_LNX_EXEC) { 219 if (esr & ESR_LNX_EXEC) {
220 vm_flags = VM_EXEC; 220 vm_flags = VM_EXEC;
221 } else if ((esr & ESR_WRITE) && !(esr & ESR_CM)) { 221 } else if ((esr & ESR_EL1_WRITE) && !(esr & ESR_EL1_CM)) {
222 vm_flags = VM_WRITE; 222 vm_flags = VM_WRITE;
223 mm_flags |= FAULT_FLAG_WRITE; 223 mm_flags |= FAULT_FLAG_WRITE;
224 } 224 }
@@ -525,7 +525,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
525 info.si_errno = 0; 525 info.si_errno = 0;
526 info.si_code = inf->code; 526 info.si_code = inf->code;
527 info.si_addr = (void __user *)addr; 527 info.si_addr = (void __user *)addr;
528 arm64_notify_die("", regs, &info, esr); 528 arm64_notify_die("", regs, &info, 0);
529 529
530 return 0; 530 return 0;
531} 531}