arm64: Provide ESR_EL1 information to user signal handlers
Catalin Marinas
maintainercover arm64: Provide ESR_EL1 information to user signal handlers
The arm64 port omitted the fault status information in sigcontext. However, there are emulators like Qemu that rely on such information to distinguish between a read or a write fault without decoding the faulting instruction.
The first patch fixes the compat case. The second patch is a clean-up and the third introduces the esr_context structure with its own magic to be stored on the signal handler stack when applicable (SIGSEGV and SIGBUS). Given that this hardware register is meant for EL1 consumption, if significant changes are made in future architecture versions a new magic number will be introduced.
Catalin Marinas (3):
arm64: Provide read/write fault information in compat signal handlers
arm64: Remove the aux_context structure
arm64: Expose ESR_EL1 information to user when SIGSEGV/SIGBUS
arch/arm64/include/asm/processor.h | 1 + arch/arm64/include/asm/sigcontext.h | 31 -------------------------- arch/arm64/include/uapi/asm/sigcontext.h | 7 ++++++ arch/arm64/kernel/signal.c | 37 +++++++++++++++++++++++--------- arch/arm64/kernel/signal32.c | 4 +++- arch/arm64/kernel/traps.c | 7 ++++-- arch/arm64/mm/fault.c | 3 ++- 7 files changed, 45 insertions(+), 45 deletions(-) delete mode 100644 arch/arm64/include/asm/sigcontext.h
Catalin Marinas
maintainerPATCH 1/3 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.
--- arch/arm64/include/asm/processor.h | 1 + arch/arm64/kernel/signal32.c | 4 +++- arch/arm64/kernel/traps.c | 7 +++++-- arch/arm64/mm/fault.c | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-)
arch/arm64/include/asm/processor.h +1 -0
@@ -79,6 +79,7 @@ struct thread_struct {unsigned long tp_value;struct fpsimd_state fpsimd_state;unsigned long fault_address;/* fault info */ +unsigned long fault_code;/* ESR_EL1 value */ struct debug_info debug;/* debugging */ };
arch/arm64/kernel/signal32.c +3 -1
@@ -500,7 +500,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 ((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); +/* compat tasks expect bit 11 as WnR status bit */ +__put_user_error ((current->thread.fault_code & (1 <<6 )) <<5 , + &sf->uc.uc_mcontext.error_code, 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);
arch/arm64/kernel/traps.c +5 -2
@@ -251,10 +251,13 @@ void die(const char *str, struct pt_regs *regs, int err)void arm64_notify_die (const char *str,struct pt_regs *regs,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); -else + }else {die (str, regs, err); + } } asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
arch/arm64/mm/fault.c +2 -1
@@ -123,6 +123,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr, } tsk->thread.fault_address = addr; + tsk->thread.fault_code = esr; si.si_signo = sig; si.si_errno =0 ; si.si_code = code;
@@ -525,7 +526,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr, info.si_errno =0 ; info.si_code = inf->code; info.si_addr = (void __user *)addr; -arm64_notify_die ("" , regs, &info, esr); +arm64_notify_die ("" , regs, &info,0 );return 0 ; }
PATCH 1/3 arm64: Provide read/write fault information in compat signal handlers
Quoted 31 lines · Catalin Marinas
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_EL1tracking for the arm64 kernel faults and sets bit 11 accordingly in compat sigcontext.Signed-off-by Catalin Marinas <[email protected]>--- arch/arm64/include/asm/processor.h | 1 + arch/arm64/kernel/signal32.c | 4 +++- arch/arm64/kernel/traps.c | 7 +++++-- arch/arm64/mm/fault.c | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-)arch/arm64/include/asm/processor.h +1
-0@@ -79,6 +79,7 @@ struct thread_struct {unsigned long tp_value;struct fpsimd_state fpsimd_state;unsigned long fault_address;/* fault info */ +unsigned long fault_code;/* ESR_EL1 value */ struct debug_info debug;/* debugging */ };arch/arm64/kernel/signal32.c +0
-0
arch/arm64/kernel/signal32.c static int compat_setup_sigframe(struct compat_sigframe __user *sf, · line 504
Quoted 6 lines
arch/arm64/kernel/signal32.c +2
-1@@ -500,7 +500,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 ((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); +/* compat tasks expect bit 11 as WnR status bit */ + __put_user_error((current->thread.fault_code & (1 << 6)) << 5,
Isn't it better to use macros for these magic values?
Thanks,
Michal
Signature · 14 lines
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91 w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/ Maintainer of Linux kernel - Xilinx Zynq ARM architecture Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 263 bytes Desc: OpenPGP digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140407/7499cd9b/attachment.sig>
Catalin Marinas
maintainerPATCH 1/3 arm64: Provide read/write fault information in compat signal handlers
Quoted 6 lines · Michal Simek
Quoted 5 lines · Catalin Marinas
arch/arm64/kernel/signal32.c +0
-0@@ -500,7 +500,9 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,__put_user_error (regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err);
Quoted 6 lines
arch/arm64/kernel/signal32.c static int compat_setup_sigframe(struct compat_sigframe __user *sf, · line 504
Quoted 4 lines
arch/arm64/kernel/signal32.c +2
-1__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); +/* compat tasks expect bit 11 as WnR status bit */ + __put_user_error((current->thread.fault_code & (1 << 6)) << 5,Isn't it better to use macros for these magic values?
I was too lazy ;). I'll add some macros.
Signature · 1 line
Catalin
Catalin Marinas
maintainerPATCH 2/3 arm64: Remove the aux_context structure
In reply to Catalin MarinasThis patch removes the aux_context structure (and the containing file) to allow the placement of the _aarch64_ctx end magic based on the context stored on the signal stack.
--- arch/arm64/include/asm/sigcontext.h | 31 ------------------------------- arch/arm64/kernel/signal.c | 27 +++++++++++++++++---------- 2 files changed, 17 insertions(+), 41 deletions(-) delete mode 100644 arch/arm64/include/asm/sigcontext.h
arch/arm64/include/asm/sigcontext.h deleted +0 -31
@@ -1,31 +0,0 @@ -/* -* Copyright (C) 2012 ARM Ltd. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __ASM_SIGCONTEXT_H -#define __ASM_SIGCONTEXT_H - -#include <uapi/asm/sigcontext.h> - -/* -* Auxiliary context saved in the sigcontext.__reserved array. Not exported to -* user space as it will change with the addition of new context. User space -* should check the magic/size information. -*/ -struct aux_context { -struct fpsimd_context fpsimd; -/* additional context to be added before "end" */ -struct _aarch64_ctx end; -}; -#endif
arch/arm64/kernel/signal.c +17 -10
@@ -100,8 +100,7 @@ static int restore_sigframe(struct pt_regs *regs, {sigset_t set;int i, err; -struct aux_context __user *aux = - (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; +void *aux = sf->uc.uc_mcontext.__reserved; err =__copy_from_user (&set, &sf->uc.uc_sigmask,sizeof (set));if (err ==0 )
@@ -121,8 +120,11 @@ static int restore_sigframe(struct pt_regs *regs, err |= !valid_user_regs (®s->user_regs); -if (err ==0 ) - err |=restore_fpsimd_context (&aux->fpsimd); +if (err ==0 ) { +struct fpsimd_context *fpsimd_ctx = + container_of(aux, struct fpsimd_context, head); + err |=restore_fpsimd_context (fpsimd_ctx); + }return err; }
@@ -167,8 +169,8 @@ static int setup_sigframe(struct rt_sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { int i, err = 0; -struct aux_context __user *aux = - (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; +void *aux = sf->uc.uc_mcontext.__reserved; +struct _aarch64_ctx *end;/* set up the stack frame for unwinding */ __put_user_error (regs->regs[29 ], &sf->fp, err);
@@ -185,12 +187,17 @@ static int setup_sigframe(struct rt_sigframe __user *sf, err |=__copy_to_user (&sf->uc.uc_sigmask, set,sizeof (*set)); -if (err ==0 ) - err |=preserve_fpsimd_context (&aux->fpsimd); +if (err ==0 ) { +struct fpsimd_context *fpsimd_ctx = + container_of(aux, struct fpsimd_context, head); + err |=preserve_fpsimd_context (fpsimd_ctx); + aux +=sizeof (*fpsimd_ctx); + }/* set the "end" magic */ -__put_user_error (0 , &aux->end.magic, err); -__put_user_error (0 , &aux->end.size, err); + end = aux; +__put_user_error (0 , &end->magic, err); +__put_user_error (0 , &end->size, err);return err; }
Catalin Marinas
maintainerPATCH 3/3 arm64: Expose ESR_EL1 information to user when SIGSEGV/SIGBUS
In reply to Catalin MarinasThis information is useful for instruction emulators to detect read/write and access size without having to decode the faulting instruction. The current patch exports it via sigcontext (struct esr_context) and is only valid for SIGSEGV and SIGBUS.
--- arch/arm64/include/uapi/asm/sigcontext.h | 7 +++++++ arch/arm64/kernel/signal.c | 10 ++++++++++ 2 files changed, 17 insertions(+)
arch/arm64/include/uapi/asm/sigcontext.h +7 -0
@@ -53,5 +53,12 @@ struct fpsimd_context { __uint128_t vregs[32]; }; +/* ESR_EL1 context */ +#define ESR_MAGIC 0x45535201 + +struct esr_context { +struct _aarch64_ctx head; +u64 esr; +};#endif /* _UAPI__ASM_SIGCONTEXT_H */
arch/arm64/kernel/signal.c +10 -0
@@ -194,6 +194,16 @@ static int setup_sigframe(struct rt_sigframe __user *sf, aux +=sizeof (*fpsimd_ctx); } +/* fault information, if valid */ +if (current->thread.fault_code) { +struct esr_context *esr_ctx = + container_of(aux, struct esr_context, head); +__put_user_error (ESR_MAGIC , &esr_ctx->head.magic, err); +__put_user_error (sizeof (*esr_ctx), &esr_ctx->head.size, err); +__put_user_error (current->thread.fault_code, &esr_ctx->esr, err); + aux +=sizeof (*esr_ctx); + } +/* set the "end" magic */ end = aux;__put_user_error (0 , &end->magic, err);