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>
This commit is contained in:
parent
6400111399
commit
9141300a58
5 changed files with 20 additions and 9 deletions
|
@ -18,9 +18,11 @@
|
||||||
#ifndef __ASM_ESR_H
|
#ifndef __ASM_ESR_H
|
||||||
#define __ASM_ESR_H
|
#define __ASM_ESR_H
|
||||||
|
|
||||||
#define ESR_EL1_EC_SHIFT (26)
|
#define ESR_EL1_WRITE (1 << 6)
|
||||||
#define ESR_EL1_IL (1U << 25)
|
#define ESR_EL1_CM (1 << 8)
|
||||||
|
#define ESR_EL1_IL (1 << 25)
|
||||||
|
|
||||||
|
#define ESR_EL1_EC_SHIFT (26)
|
||||||
#define ESR_EL1_EC_UNKNOWN (0x00)
|
#define ESR_EL1_EC_UNKNOWN (0x00)
|
||||||
#define ESR_EL1_EC_WFI (0x01)
|
#define ESR_EL1_EC_WFI (0x01)
|
||||||
#define ESR_EL1_EC_CP15_32 (0x03)
|
#define ESR_EL1_EC_CP15_32 (0x03)
|
||||||
|
|
|
@ -79,6 +79,7 @@ struct thread_struct {
|
||||||
unsigned long tp_value;
|
unsigned long tp_value;
|
||||||
struct fpsimd_state fpsimd_state;
|
struct fpsimd_state fpsimd_state;
|
||||||
unsigned long fault_address; /* fault info */
|
unsigned long fault_address; /* fault info */
|
||||||
|
unsigned long fault_code; /* ESR_EL1 value */
|
||||||
struct debug_info debug; /* debugging */
|
struct debug_info debug; /* debugging */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
|
|
||||||
|
#include <asm/esr.h>
|
||||||
#include <asm/fpsimd.h>
|
#include <asm/fpsimd.h>
|
||||||
#include <asm/signal32.h>
|
#include <asm/signal32.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
@ -81,6 +82,8 @@ struct compat_vfp_sigframe {
|
||||||
#define VFP_MAGIC 0x56465001
|
#define VFP_MAGIC 0x56465001
|
||||||
#define VFP_STORAGE_SIZE sizeof(struct compat_vfp_sigframe)
|
#define VFP_STORAGE_SIZE sizeof(struct compat_vfp_sigframe)
|
||||||
|
|
||||||
|
#define FSR_WRITE_SHIFT (11)
|
||||||
|
|
||||||
struct compat_aux_sigframe {
|
struct compat_aux_sigframe {
|
||||||
struct compat_vfp_sigframe vfp;
|
struct compat_vfp_sigframe vfp;
|
||||||
|
|
||||||
|
@ -500,7 +503,9 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,
|
||||||
__put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
|
__put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
|
||||||
|
|
||||||
__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err);
|
__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err);
|
||||||
__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.error_code, err);
|
/* set the compat FSR WnR */
|
||||||
|
__put_user_error(!!(current->thread.fault_code & ESR_EL1_WRITE) <<
|
||||||
|
FSR_WRITE_SHIFT, &sf->uc.uc_mcontext.error_code, err);
|
||||||
__put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
|
__put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
|
||||||
__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
|
__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
|
||||||
|
|
||||||
|
|
|
@ -251,11 +251,14 @@ void die(const char *str, struct pt_regs *regs, int err)
|
||||||
void arm64_notify_die(const char *str, struct pt_regs *regs,
|
void arm64_notify_die(const char *str, struct pt_regs *regs,
|
||||||
struct siginfo *info, int err)
|
struct siginfo *info, int err)
|
||||||
{
|
{
|
||||||
if (user_mode(regs))
|
if (user_mode(regs)) {
|
||||||
|
current->thread.fault_address = 0;
|
||||||
|
current->thread.fault_code = err;
|
||||||
force_sig_info(info->si_signo, info, current);
|
force_sig_info(info->si_signo, info, current);
|
||||||
else
|
} else {
|
||||||
die(str, regs, err);
|
die(str, regs, err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include <asm/exception.h>
|
#include <asm/exception.h>
|
||||||
#include <asm/debug-monitors.h>
|
#include <asm/debug-monitors.h>
|
||||||
|
#include <asm/esr.h>
|
||||||
#include <asm/system_misc.h>
|
#include <asm/system_misc.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
|
@ -123,6 +124,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
tsk->thread.fault_address = addr;
|
tsk->thread.fault_address = addr;
|
||||||
|
tsk->thread.fault_code = esr;
|
||||||
si.si_signo = sig;
|
si.si_signo = sig;
|
||||||
si.si_errno = 0;
|
si.si_errno = 0;
|
||||||
si.si_code = code;
|
si.si_code = code;
|
||||||
|
@ -148,8 +150,6 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
|
||||||
#define VM_FAULT_BADMAP 0x010000
|
#define VM_FAULT_BADMAP 0x010000
|
||||||
#define VM_FAULT_BADACCESS 0x020000
|
#define VM_FAULT_BADACCESS 0x020000
|
||||||
|
|
||||||
#define ESR_WRITE (1 << 6)
|
|
||||||
#define ESR_CM (1 << 8)
|
|
||||||
#define ESR_LNX_EXEC (1 << 24)
|
#define ESR_LNX_EXEC (1 << 24)
|
||||||
|
|
||||||
static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
|
static 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,
|
||||||
|
|
||||||
if (esr & ESR_LNX_EXEC) {
|
if (esr & ESR_LNX_EXEC) {
|
||||||
vm_flags = VM_EXEC;
|
vm_flags = VM_EXEC;
|
||||||
} else if ((esr & ESR_WRITE) && !(esr & ESR_CM)) {
|
} else if ((esr & ESR_EL1_WRITE) && !(esr & ESR_EL1_CM)) {
|
||||||
vm_flags = VM_WRITE;
|
vm_flags = VM_WRITE;
|
||||||
mm_flags |= FAULT_FLAG_WRITE;
|
mm_flags |= FAULT_FLAG_WRITE;
|
||||||
}
|
}
|
||||||
|
@ -525,7 +525,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = inf->code;
|
info.si_code = inf->code;
|
||||||
info.si_addr = (void __user *)addr;
|
info.si_addr = (void __user *)addr;
|
||||||
arm64_notify_die("", regs, &info, esr);
|
arm64_notify_die("", regs, &info, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue