diff options
author | Koen Kooi <koen@openembedded.org> | 2009-08-16 11:34:38 +0200 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2009-08-16 11:34:38 +0200 |
commit | 97aee9aeb0da17f7c3a3c31acf5f8ddd227bd3e2 (patch) | |
tree | c6f9e1aa40a5abfde9d03de2fb4f86e778ef8ffd /recipes/linux/linux-omap-pm-2.6.29/vfp | |
parent | 2001d352e87a4a143c6dd4bed2d3261937c16eba (diff) |
linux-omap-pm 2.6.29: update to latest git HEAD, sync patches and defconfig with regular linux-omap 2.6.29
Diffstat (limited to 'recipes/linux/linux-omap-pm-2.6.29/vfp')
5 files changed, 741 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch new file mode 100644 index 0000000000..70d4d1efc5 --- /dev/null +++ b/recipes/linux/linux-omap-pm-2.6.29/vfp/01-vfp-pm.patch @@ -0,0 +1,128 @@ +From: Ben Dooks <ben-linux@fluff.org> +Date: Thu, 18 Dec 2008 10:26:54 +0000 (+0100) +Subject: 5349/1: VFP: Add PM code to save and restore current VFP state +X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=d504d72ad38e54b5feda67e956834348d6a500e1 + +5349/1: VFP: Add PM code to save and restore current VFP state + +[ARM] 5349/1: VFP: Add PM code to save and restore current VFP state + +When CONFIG_PM is selected, the VFP code does not have any handler +installed to deal with either saving the VFP state of the current +task, nor does it do anything to try and restore the VFP after a +resume. + +On resume, the VFP will have been reset and the co-processor access +control registers are in an indeterminate state (very probably the +CP10 and CP11 the VFP uses will have been disabled by the ARM core +reset). When this happens, resume will break as soon as it tries to +unfreeze the tasks and restart scheduling. + +Add a sys device to allow us to hook the suspend call to save the +current thread state if the thread is using VFP and a resume hook +which restores the CP10/CP11 access and ensures the VFP is disabled +so that the lazy swapping will take place on next access. + +Signed-off-by: Ben Dooks <ben-linux@fluff.org> +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +--- + +diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h +index c85860b..8de86e4 100644 +--- a/arch/arm/vfp/vfp.h ++++ b/arch/arm/vfp/vfp.h +@@ -377,6 +377,6 @@ struct op { + u32 flags; + }; + +-#ifdef CONFIG_SMP ++#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 a62dcf7..b21f43f 100644 +--- a/arch/arm/vfp/vfphw.S ++++ b/arch/arm/vfp/vfphw.S +@@ -166,7 +166,7 @@ process_exception: + @ retry the faulted instruction + ENDPROC(vfp_support_entry) + +-#ifdef CONFIG_SMP ++#if defined(CONFIG_SMP) || defined(CONFIG_PM) + ENTRY(vfp_save_state) + @ Save the current VFP state + @ r0 - save location +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 67ca340..9f476a1 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -322,6 +322,61 @@ static void vfp_enable(void *unused) + set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11)); + } + ++#ifdef CONFIG_PM ++#include <linux/sysdev.h> ++ ++static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) ++{ ++ struct thread_info *ti = current_thread_info(); ++ u32 fpexc = fmrx(FPEXC); ++ ++ /* if vfp is on, then save state for resumption */ ++ if (fpexc & FPEXC_EN) { ++ printk(KERN_DEBUG "%s: saving vfp state\n", __func__); ++ vfp_save_state(&ti->vfpstate, fpexc); ++ ++ /* disable, just in case */ ++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); ++ } ++ ++ /* clear any information we had about last context state */ ++ memset(last_VFP_context, 0, sizeof(last_VFP_context)); ++ ++ return 0; ++} ++ ++static int vfp_pm_resume(struct sys_device *dev) ++{ ++ /* ensure we have access to the vfp */ ++ vfp_enable(NULL); ++ ++ /* and disable it to ensure the next usage restores the state */ ++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); ++ ++ return 0; ++} ++ ++static struct sysdev_class vfp_pm_sysclass = { ++ .name = "vfp", ++ .suspend = vfp_pm_suspend, ++ .resume = vfp_pm_resume, ++}; ++ ++static struct sys_device vfp_pm_sysdev = { ++ .cls = &vfp_pm_sysclass, ++}; ++ ++static void vfp_pm_init(void) ++{ ++ sysdev_class_register(&vfp_pm_sysclass); ++ sysdev_register(&vfp_pm_sysdev); ++} ++ ++ ++#else ++static inline void vfp_pm_init(void) { } ++#endif /* CONFIG_PM */ ++ + #include <linux/smp.h> + + /* +@@ -365,6 +420,7 @@ static int __init vfp_init(void) + vfp_vector = vfp_support_entry; + + thread_register_notifier(&vfp_notifier_block); ++ vfp_pm_init(); + + /* + * We detected VFP, and the support code is diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/02-vfp-ptrace.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/02-vfp-ptrace.patch new file mode 100644 index 0000000000..feba206f95 --- /dev/null +++ b/recipes/linux/linux-omap-pm-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> + + /* diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/03-vfp-corruption.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/03-vfp-corruption.patch new file mode 100644 index 0000000000..216d4f5eaa --- /dev/null +++ b/recipes/linux/linux-omap-pm-2.6.29/vfp/03-vfp-corruption.patch @@ -0,0 +1,136 @@ +From: George G. Davis <gdavis@mvista.com> +Date: Wed, 1 Apr 2009 18:27:18 +0000 (+0100) +Subject: 5440/1: Fix VFP state corruption due to preemption during VFP exceptions +X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=4f7720780dc4a298a6d59c0ec39f7687022cc36f + +5440/1: Fix VFP state corruption due to preemption during VFP exceptions + +[ARM] 5440/1: Fix VFP state corruption due to preemption during VFP exceptions + +We've observed that ARM VFP state can be corrupted during VFP exception +handling when PREEMPT is enabled. The exact conditions are difficult +to reproduce but appear to occur during VFP exception handling when a +task causes a VFP exception which is handled via VFP_bounce and is then +preempted by yet another task which in turn causes yet another VFP +exception. Since the VFP_bounce code is not preempt safe, VFP state then +becomes corrupt. In order to prevent preemption from occuring while +handling a VFP exception, this patch disables preemption while handling +VFP exceptions. + +Signed-off-by: George G. Davis <gdavis@mvista.com> +Acked-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> +--- + +diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S +index ba592a9..a2bed62 100644 +--- a/arch/arm/vfp/entry.S ++++ b/arch/arm/vfp/entry.S +@@ -15,13 +15,16 @@ + * r10 = thread_info structure + * lr = failure return + */ +-#include <linux/linkage.h> +-#include <linux/init.h> +-#include <asm/asm-offsets.h> +-#include <asm/assembler.h> ++#include <asm/thread_info.h> + #include <asm/vfpmacros.h> ++#include "../kernel/entry-header.S" + + ENTRY(do_vfp) ++#ifdef CONFIG_PREEMPT ++ ldr r4, [r10, #TI_PREEMPT] @ get preempt count ++ add r11, r4, #1 @ increment it ++ str r11, [r10, #TI_PREEMPT] ++#endif + enable_irq + ldr r4, .LCvfp + ldr r11, [r10, #TI_CPU] @ CPU number +@@ -30,6 +33,12 @@ ENTRY(do_vfp) + ENDPROC(do_vfp) + + ENTRY(vfp_null_entry) ++#ifdef CONFIG_PREEMPT ++ get_thread_info r10 ++ ldr r4, [r10, #TI_PREEMPT] @ get preempt count ++ sub r11, r4, #1 @ decrement it ++ str r11, [r10, #TI_PREEMPT] ++#endif + mov pc, lr + ENDPROC(vfp_null_entry) + +@@ -41,6 +50,12 @@ ENDPROC(vfp_null_entry) + + __INIT + ENTRY(vfp_testing_entry) ++#ifdef CONFIG_PREEMPT ++ get_thread_info r10 ++ ldr r4, [r10, #TI_PREEMPT] @ get preempt count ++ sub r11, r4, #1 @ decrement it ++ str r11, [r10, #TI_PREEMPT] ++#endif + ldr r0, VFP_arch_address + str r5, [r0] @ known non-zero value + mov pc, r9 @ we have handled the fault +diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S +index 902d396..ea0a156 100644 +--- a/arch/arm/vfp/vfphw.S ++++ b/arch/arm/vfp/vfphw.S +@@ -131,6 +131,12 @@ check_for_exception: + VFPFMXR FPEXC, r1 @ restore FPEXC last + sub r2, r2, #4 + str r2, [sp, #S_PC] @ retry the instruction ++#ifdef CONFIG_PREEMPT ++ get_thread_info r10 ++ ldr r4, [r10, #TI_PREEMPT] @ get preempt count ++ sub r11, r4, #1 @ decrement it ++ str r11, [r10, #TI_PREEMPT] ++#endif + mov pc, r9 @ we think we have handled things + + +@@ -149,6 +155,12 @@ look_for_VFP_exceptions: + @ not recognised by VFP + + DBGSTR "not VFP" ++#ifdef CONFIG_PREEMPT ++ get_thread_info r10 ++ ldr r4, [r10, #TI_PREEMPT] @ get preempt count ++ sub r11, r4, #1 @ decrement it ++ str r11, [r10, #TI_PREEMPT] ++#endif + mov pc, lr + + process_exception: +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 75457b3..01599c4 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -266,7 +266,7 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + * on VFP subarch 1. + */ + vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); +- return; ++ goto exit; + } + + /* +@@ -297,7 +297,7 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. + */ + if (fpexc ^ (FPEXC_EX | FPEXC_FP2V)) +- return; ++ goto exit; + + /* + * The barrier() here prevents fpinst2 being read +@@ -310,6 +310,8 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) + exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); + if (exceptions) + vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); ++ exit: ++ preempt_enable(); + } + + static void vfp_enable(void *unused) diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/04-vfp-threads.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/04-vfp-threads.patch new file mode 100644 index 0000000000..221b2774a1 --- /dev/null +++ b/recipes/linux/linux-omap-pm-2.6.29/vfp/04-vfp-threads.patch @@ -0,0 +1,98 @@ +From: Imre Deak <imre.deak@nokia.com> +Date: Wed, 1 Jul 2009 21:20:59 +0000 (+0300) +Subject: So far vfp_sync_state worked only for threads other than the current one. This worked... +X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=23671113997664ae55c8132fc4a56e676d5b46c7 + +So far vfp_sync_state worked only for threads other than the current one. This worked for tracing other threads, but not for PTRACE_TRACEME. Syncing for the current thread will also be needed by an upcoming patch adding support for VFP context save / restore around signal handlers. + +For SMP we need get_cpu now, since we have to protect the FPEXC +register, other than this things remained the same for threads other +than the current. + +Signed-off-by: Imre Deak <imre.deak@nokia.com> +--- + +diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c +index 01599c4..969b77a 100644 +--- a/arch/arm/vfp/vfpmodule.c ++++ b/arch/arm/vfp/vfpmodule.c +@@ -380,12 +380,19 @@ 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. ++ * Synchronise the hardware VFP state of a thread with the saved one. ++ * This function is used by the ptrace mechanism and the signal handler path. + */ +-#ifdef CONFIG_SMP + void vfp_sync_state(struct thread_info *thread) + { ++ unsigned int cpu = get_cpu(); ++ u32 fpexc = fmrx(FPEXC); ++ int vfp_enabled; ++ int self; ++ ++ vfp_enabled = fpexc & FPEXC_EN; ++ self = thread == current_thread_info(); ++#ifdef CONFIG_SMP + /* + * On SMP systems, the VFP state is automatically saved at every + * context switch. We mark the thread VFP state as belonging to a +@@ -393,18 +400,22 @@ void vfp_sync_state(struct thread_info *thread) + * 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. ++ * Only the current thread's saved VFP context can be out-of-date. ++ * For others there is nothing else to do, since we already ensured ++ * force loading above. + */ +- if (fpexc & FPEXC_EN) ++ if (!self) ++ goto out; ++#endif ++ /* ++ * If the VFP is enabled only the current thread's saved VFP ++ * context can get out-of-date. For other threads the context ++ * was updated when the current thread started to use the VFP. ++ * This also means that the context will be reloaded next time ++ * the thread uses the VFP, so no need to enforce it. ++ */ ++ if (vfp_enabled && !self) + goto out; + + if (!last_VFP_context[cpu]) +@@ -413,8 +424,14 @@ void vfp_sync_state(struct thread_info *thread) + /* + * Save the last VFP state on this CPU. + */ +- fmxr(FPEXC, fpexc | FPEXC_EN); ++ if (!vfp_enabled) ++ fmxr(FPEXC, fpexc | FPEXC_EN); + vfp_save_state(last_VFP_context[cpu], fpexc); ++ /* ++ * Disable VFP in case it was enabled so that the force reload ++ * can happen. ++ */ ++ fpexc &= ~FPEXC_EN; + fmxr(FPEXC, fpexc); + + /* +@@ -426,7 +443,6 @@ void vfp_sync_state(struct thread_info *thread) + out: + put_cpu(); + } +-#endif + + #include <linux/smp.h> + diff --git a/recipes/linux/linux-omap-pm-2.6.29/vfp/05-vfp-signal-handlers.patch b/recipes/linux/linux-omap-pm-2.6.29/vfp/05-vfp-signal-handlers.patch new file mode 100644 index 0000000000..f648188584 --- /dev/null +++ b/recipes/linux/linux-omap-pm-2.6.29/vfp/05-vfp-signal-handlers.patch @@ -0,0 +1,148 @@ +From: Imre Deak <imre.deak@nokia.com> +Date: Wed, 1 Jul 2009 21:21:06 +0000 (+0300) +Subject: Signal handlers can use floating point, so prevent them to corrupt the main thread... +X-Git-Url: http://siarhei.siamashka.name/gitweb/?p=linux-omap-2.6.git;a=commitdiff_plain;h=4daa6b5d833c401a9de6f136ea23daa971fc4fdc + +Signal handlers can use floating point, so prevent them to corrupt the main thread's VFP context. So far there were two signal stack frame formats defined based on the VFP implementation, but recently a new user struct was added for ptrace that covers all possibilities, so use it for the signal stack too. + +Signed-off-by: Imre Deak <imre.deak@nokia.com> +--- + +diff --git a/arch/arm/include/asm/ucontext.h b/arch/arm/include/asm/ucontext.h +index bf65e9f..5534653 100644 +--- a/arch/arm/include/asm/ucontext.h ++++ b/arch/arm/include/asm/ucontext.h +@@ -59,23 +59,19 @@ struct iwmmxt_sigframe { + #endif /* CONFIG_IWMMXT */ + + #ifdef CONFIG_VFP +-#if __LINUX_ARM_ARCH__ < 6 +-/* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra +- * word after the registers, and a word of padding at the end for +- * alignment. */ + #define VFP_MAGIC 0x56465001 +-#define VFP_STORAGE_SIZE 152 +-#else +-#define VFP_MAGIC 0x56465002 +-#define VFP_STORAGE_SIZE 144 +-#endif + + struct vfp_sigframe + { + unsigned long magic; + unsigned long size; +- union vfp_state storage; +-}; ++ struct user_vfp ufp; ++ unsigned long reserved; ++} __attribute__((__aligned__(8))); ++ ++/* 8 byte for magic and size, 260 byte for ufp and 4 byte padding */ ++#define VFP_STORAGE_SIZE sizeof(struct vfp_sigframe) ++ + #endif /* CONFIG_VFP */ + + /* +@@ -91,7 +87,7 @@ struct aux_sigframe { + #ifdef CONFIG_IWMMXT + struct iwmmxt_sigframe iwmmxt; + #endif +-#if 0 && defined CONFIG_VFP /* Not yet saved. */ ++#ifdef CONFIG_VFP + struct vfp_sigframe vfp; + #endif + /* Something that isn't a valid magic number for any coprocessor. */ +diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c +index 80b8b5c..a5ef7f5 100644 +--- a/arch/arm/kernel/signal.c ++++ b/arch/arm/kernel/signal.c +@@ -196,6 +196,67 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) + + #endif + ++#ifdef CONFIG_VFP ++ ++static int preserve_vfp_context(struct vfp_sigframe __user *frame) ++{ ++ struct thread_info *thread = current_thread_info(); ++ struct vfp_hard_struct *h = &thread->vfpstate.hard; ++ const unsigned long magic = VFP_MAGIC; ++ const unsigned long size = VFP_STORAGE_SIZE; ++ int err = 0; ++ ++ vfp_sync_state(thread); ++ __put_user_error(magic, &frame->magic, err); ++ __put_user_error(size, &frame->size, err); ++ ++ /* ++ * Copy the floating point registers. There can be unused ++ * registers see asm/hwcap.h for details. ++ */ ++ err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs, ++ sizeof(h->fpregs)); ++ /* ++ * Copy the status and control register. ++ */ ++ __put_user_error(h->fpscr, &frame->ufp.fpscr, err); ++ ++ return err ? -EFAULT : 0; ++} ++ ++static int restore_vfp_context(struct vfp_sigframe __user *frame) ++{ ++ struct thread_info *thread = current_thread_info(); ++ struct vfp_hard_struct *h = &thread->vfpstate.hard; ++ unsigned long magic; ++ unsigned long size; ++ int err = 0; ++ ++ vfp_sync_state(thread); ++ __get_user_error(magic, &frame->magic, err); ++ __get_user_error(size, &frame->size, err); ++ ++ if (err) ++ return -EFAULT; ++ if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) ++ return -EINVAL; ++ ++ /* ++ * Copy the floating point registers. There can be unused ++ * registers see asm/hwcap.h for details. ++ */ ++ err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs, ++ sizeof(h->fpregs)); ++ /* ++ * Copy the status and control register. ++ */ ++ __get_user_error(h->fpscr, &frame->ufp.fpscr, err); ++ ++ return err ? -EFAULT : 0; ++} ++ ++#endif ++ + /* + * Do a signal return; undo the signal stack. These are aligned to 64-bit. + */ +@@ -254,8 +315,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) + err |= restore_iwmmxt_context(&aux->iwmmxt); + #endif + #ifdef CONFIG_VFP +-// if (err == 0) +-// err |= vfp_restore_state(&sf->aux.vfp); ++ if (err == 0) ++ err |= restore_vfp_context(&aux->vfp); + #endif + + return err; +@@ -369,8 +430,8 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) + err |= preserve_iwmmxt_context(&aux->iwmmxt); + #endif + #ifdef CONFIG_VFP +-// if (err == 0) +-// err |= vfp_save_state(&sf->aux.vfp); ++ if (err == 0) ++ err |= preserve_vfp_context(&aux->vfp); + #endif + __put_user_error(0, &aux->end_magic, err); + |