diff options
Diffstat (limited to 'recipes/kexecboot/linux-kexecboot-2.6.29/vfp/02-vfp-ptrace.patch')
-rw-r--r-- | recipes/kexecboot/linux-kexecboot-2.6.29/vfp/02-vfp-ptrace.patch | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/recipes/kexecboot/linux-kexecboot-2.6.29/vfp/02-vfp-ptrace.patch b/recipes/kexecboot/linux-kexecboot-2.6.29/vfp/02-vfp-ptrace.patch new file mode 100644 index 0000000000..feba206f95 --- /dev/null +++ b/recipes/kexecboot/linux-kexecboot-2.6.29/vfp/02-vfp-ptrace.patch @@ -0,0 +1,231 @@ +From: Catalin Marinas <catalin.marinas@arm.com> +Date: Wed, 11 Feb 2009 11:12:56 +0000 (+0100) +Subject: 5387/1: Add ptrace VFP support on ARM +X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=4dd5beb2244f15c895aba46474bd89545327d1a6 + +5387/1: Add ptrace VFP support on ARM + +[ARM] 5387/1: Add ptrace VFP support on ARM + +This patch adds ptrace support for setting and getting the VFP registers +using PTRACE_SETVFPREGS and PTRACE_GETVFPREGS. The user_vfp structure +defined in asm/user.h contains 32 double registers (to cover VFPv3 and +Neon hardware) and the FPSCR register. + +Cc: Paul Brook <paul@codesourcery.com> +Cc: Daniel Jacobowitz <dan@codesourcery.com> +Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +--- + +diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h +index 7319261..236a06b 100644 +--- a/arch/arm/include/asm/ptrace.h ++++ b/arch/arm/include/asm/ptrace.h +@@ -27,6 +27,8 @@ + /* PTRACE_SYSCALL is 24 */ + #define PTRACE_GETCRUNCHREGS 25 + #define PTRACE_SETCRUNCHREGS 26 ++#define PTRACE_GETVFPREGS 27 ++#define PTRACE_SETVFPREGS 28 + + /* + * PSR bits +diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h +index 68b9ec8..b9dc8a8 100644 +--- a/arch/arm/include/asm/thread_info.h ++++ b/arch/arm/include/asm/thread_info.h +@@ -113,6 +113,8 @@ extern void iwmmxt_task_restore(struct thread_info *, void *); + extern void iwmmxt_task_release(struct thread_info *); + extern void iwmmxt_task_switch(struct thread_info *); + ++extern void vfp_sync_state(struct thread_info *thread); ++ + #endif + + /* +diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h +index 825c1e7..df95e05 100644 +--- a/arch/arm/include/asm/user.h ++++ b/arch/arm/include/asm/user.h +@@ -81,4 +81,13 @@ struct user{ + #define HOST_TEXT_START_ADDR (u.start_code) + #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + ++/* ++ * User specific VFP registers. If only VFPv2 is present, registers 16 to 31 ++ * are ignored by the ptrace system call. ++ */ ++struct user_vfp { ++ unsigned long long fpregs[32]; ++ unsigned long fpscr; ++}; ++ + #endif /* _ARM_USER_H */ +diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c +index df653ea..89882a1 100644 +--- a/arch/arm/kernel/ptrace.c ++++ b/arch/arm/kernel/ptrace.c +@@ -653,6 +653,54 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) + } + #endif + ++#ifdef CONFIG_VFP ++/* ++ * Get the child VFP state. ++ */ ++static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) ++{ ++ struct thread_info *thread = task_thread_info(tsk); ++ union vfp_state *vfp = &thread->vfpstate; ++ struct user_vfp __user *ufp = data; ++ ++ vfp_sync_state(thread); ++ ++ /* copy the floating point registers */ ++ if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, ++ sizeof(vfp->hard.fpregs))) ++ return -EFAULT; ++ ++ /* copy the status and control register */ ++ if (put_user(vfp->hard.fpscr, &ufp->fpscr)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* ++ * Set the child VFP state. ++ */ ++static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) ++{ ++ struct thread_info *thread = task_thread_info(tsk); ++ union vfp_state *vfp = &thread->vfpstate; ++ struct user_vfp __user *ufp = data; ++ ++ vfp_sync_state(thread); ++ ++ /* copy the floating point registers */ ++ if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, ++ sizeof(vfp->hard.fpregs))) ++ return -EFAULT; ++ ++ /* copy the status and control register */ ++ if (get_user(vfp->hard.fpscr, &ufp->fpscr)) ++ return -EFAULT; ++ ++ return 0; ++} ++#endif ++ + long arch_ptrace(struct task_struct *child, long request, long addr, long data) + { + int ret; +@@ -775,6 +823,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) + break; + #endif + ++#ifdef CONFIG_VFP ++ case PTRACE_GETVFPREGS: ++ ret = ptrace_getvfpregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_SETVFPREGS: ++ ret = ptrace_setvfpregs(child, (void __user *)data); ++ break; ++#endif ++ + default: + ret = ptrace_request(child, request, addr, data); + break; +diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h +index 8de86e4..c8c98dd 100644 +--- a/arch/arm/vfp/vfp.h ++++ b/arch/arm/vfp/vfp.h +@@ -377,6 +377,4 @@ struct op { + u32 flags; + }; + +-#if defined(CONFIG_SMP) || defined(CONFIG_PM) + extern void vfp_save_state(void *location, u32 fpexc); +-#endif +diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S +index b21f43f..902d396 100644 +--- a/arch/arm/vfp/vfphw.S ++++ b/arch/arm/vfp/vfphw.S +@@ -166,7 +166,6 @@ process_exception: + @ retry the faulted instruction + ENDPROC(vfp_support_entry) + +-#if defined(CONFIG_SMP) || defined(CONFIG_PM) + ENTRY(vfp_save_state) + @ Save the current VFP state + @ r0 - save location +@@ -181,7 +180,6 @@ ENTRY(vfp_save_state) + stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2 + mov pc, lr + ENDPROC(vfp_save_state) +-#endif + + last_VFP_context_address: + .word last_VFP_context +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 9f476a1..7e12390 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -377,6 +377,55 @@ static void vfp_pm_init(void) + static inline void vfp_pm_init(void) { } + #endif /* CONFIG_PM */ + ++/* ++ * Synchronise the hardware VFP state of a thread other than current with the ++ * saved one. This function is used by the ptrace mechanism. ++ */ ++#ifdef CONFIG_SMP ++void vfp_sync_state(struct thread_info *thread) ++{ ++ /* ++ * On SMP systems, the VFP state is automatically saved at every ++ * context switch. We mark the thread VFP state as belonging to a ++ * non-existent CPU so that the saved one will be reloaded when ++ * needed. ++ */ ++ thread->vfpstate.hard.cpu = NR_CPUS; ++} ++#else ++void vfp_sync_state(struct thread_info *thread) ++{ ++ unsigned int cpu = get_cpu(); ++ u32 fpexc = fmrx(FPEXC); ++ ++ /* ++ * If VFP is enabled, the previous state was already saved and ++ * last_VFP_context updated. ++ */ ++ if (fpexc & FPEXC_EN) ++ goto out; ++ ++ if (!last_VFP_context[cpu]) ++ goto out; ++ ++ /* ++ * Save the last VFP state on this CPU. ++ */ ++ fmxr(FPEXC, fpexc | FPEXC_EN); ++ vfp_save_state(last_VFP_context[cpu], fpexc); ++ fmxr(FPEXC, fpexc); ++ ++ /* ++ * Set the context to NULL to force a reload the next time the thread ++ * uses the VFP. ++ */ ++ last_VFP_context[cpu] = NULL; ++ ++out: ++ put_cpu(); ++} ++#endif ++ + #include <linux/smp.h> + + /* |