Preserve the VFP state across the fork() call
Subsystems (2)
cover Preserve the VFP state across the fork() call
The VFP state should be copied to the child process during the fork() system call. This is important because the d16-d31 registers are callee saved and the compiler may use them for preserving data across function calls.
Catalin Marinas (2):
ARM: Introduce THREAD_NOTIFY_COPY for copy_thread() hooks
ARM: Preserve the VFP state during fork
arch/arm/include/asm/thread_notify.h | 1 + arch/arm/kernel/process.c | 2 ++ arch/arm/vfp/vfpmodule.c | 34 +++++++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 7 deletions(-)
Signature · 1 line
Catalin
PATCH 1/2 ARM: Introduce THREAD_NOTIFY_COPY for copy_thread() hooks
This patch adds THREAD_NOTIFY_COPY for colling registered handlers during the copy_thread() function call. It also changes the VFP handler to use a switch statement rather than if..else and ignore this event.
--- arch/arm/include/asm/thread_notify.h | 1 + arch/arm/kernel/process.c | 2 ++ arch/arm/vfp/vfpmodule.c | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 7 deletions(-)
arch/arm/include/asm/thread_notify.h +1 -0
@@ -43,6 +43,7 @@ static inline void thread_notify(unsigned long rc, struct thread_info *thread)#define THREAD_NOTIFY_FLUSH 0#define THREAD_NOTIFY_EXIT 1#define THREAD_NOTIFY_SWITCH 2 +#define THREAD_NOTIFY_COPY 3#endif #endif
arch/arm/kernel/process.c +2 -0
@@ -372,6 +372,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,if (clone_flags &CLONE_SETTLS ) thread->tp_value = regs->ARM_r3; +thread_notify (THREAD_NOTIFY_COPY , thread); +return 0 ; }
arch/arm/vfp/vfpmodule.c +15 -7
@@ -104,12 +104,17 @@ static void vfp_thread_exit(struct thread_info *thread)static int vfp_notifier (struct notifier_block *self,unsigned long cmd,void *v) {struct thread_info *thread = v; +u32 fpexc; +#ifdef CONFIG_SMP +unsigned int cpu; +#endif -if (likely (cmd ==THREAD_NOTIFY_SWITCH )) { -u32 fpexc =fmrx (FPEXC ); +switch (cmd) { +case THREAD_NOTIFY_SWITCH : + fpexc =fmrx (FPEXC );#ifdef CONFIG_SMP -unsigned int cpu = thread->cpu; + cpu = thread->cpu;/* * On SMP, if VFP is enabled, save the old state in
@@ -134,13 +139,16 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)* old state. */ fmxr (FPEXC , fpexc & ~FPEXC_EN ); -return NOTIFY_DONE ; - } +break ; -if (cmd ==THREAD_NOTIFY_FLUSH ) +case THREAD_NOTIFY_FLUSH :vfp_thread_flush (thread); -else +break ; + +case THREAD_NOTIFY_EXIT :vfp_thread_exit (thread); +break ; + }return NOTIFY_DONE ; }
PATCH 1/2 ARM: Introduce THREAD_NOTIFY_COPY for copy_thread() hooks
Hi Catalin,
Quoted 6 lines
Subject: [PATCH 1/2] ARM: Introduce
THREAD_NOTIFY_COPYforcopy_thread()hooksThis patch adds
THREAD_NOTIFY_COPYfor colling registered handlers during thecopy_thread()function call. It also changes the VFP handler to use a switch statement rather than if..else and ignore this event.
Quoted 6 lines
Signed-off-by Catalin Marinas <[email protected]>--- arch/arm/include/asm/thread_notify.h | 1 + arch/arm/kernel/process.c | 2 ++ arch/arm/vfp/vfpmodule.c | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 7 deletions(-)
This would be useful for the hw-breakpoint code, where we need to clear (memset 0) the breakpoint structures in the child so that they don't get unregistered later on.
However, we also need to flush (unregister) breakpoints in flush_thread so that they don't persist across an exec. Ideally, we'd have a single notifier block and act on THREAD_NOTIFY_{FLUSH,COPY} accordingly, but the problem is that THREAD_NOTIFY_FLUSH is only notified *after* zeroing most of the thread structure, so the call is currently inlined into flush_thread and we don't use a notifier.
This could be solved by either notifying the FLUSH before zeroing the various thread structures or by moving the zeroing of the debug struct into the hw-breakpoint notifier. The latter probably makes more sense once we've removed the single-step functionality from ptrace.
Will
PATCH 1/2 ARM: Introduce THREAD_NOTIFY_COPY for copy_thread() hooks
Quoted 19 lines · Will Deacon
Hi Catalin,
Quoted 6 lines
Subject: [PATCH 1/2] ARM: Introduce
THREAD_NOTIFY_COPYforcopy_thread()hooksThis patch adds
THREAD_NOTIFY_COPYfor colling registered handlers during thecopy_thread()function call. It also changes the VFP handler to use a switch statement rather than if..else and ignore this event.Quoted 6 lines
Signed-off-by Catalin Marinas <[email protected]>--- arch/arm/include/asm/thread_notify.h | 1 + arch/arm/kernel/process.c | 2 ++ arch/arm/vfp/vfpmodule.c | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 7 deletions(-)This would be useful for the hw-breakpoint code, where we need to clear (memset 0) the breakpoint structures in the child so that they don't get unregistered later on.
Quoted 6 lines
However, we also need to flush (unregister) breakpoints in
flush_threadso that they don't persist across an exec. Ideally, we'd have a single notifier block and act on THREAD_NOTIFY_{FLUSH,COPY} accordingly, but the problem is thatTHREAD_NOTIFY_FLUSHis only notified *after* zeroing most of the thread structure, so the call is currently inlined intoflush_threadand we don't use a notifier.
It's better to avoid the thread notifier if you don't need all the facilities it offers as it gets called for every thread switch. Every additional registration will add additional cycles to the thread switch.
PATCH 2/2 ARM: Preserve the VFP state during fork
In reply to Catalin MarinasVFP registers d16-d31 are callee saved registers and must be preserved during function calls, including fork(). The VFP configuration should also be preserved. The patch copies the full VFP state to the child process.
--- arch/arm/vfp/vfpmodule.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
arch/arm/vfp/vfpmodule.c +12 -0
@@ -78,6 +78,14 @@ static void vfp_thread_exit(struct thread_info *thread)put_cpu (); } +static void vfp_thread_copy (struct thread_info *thread) +{ +struct thread_info *parent =current_thread_info (); + +vfp_sync_hwstate (parent); + thread->vfpstate = parent->vfpstate; +} +/* * When this function is called with the following 'cmd's, the following * is true while this function is being run:
@@ -148,6 +156,10 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)case THREAD_NOTIFY_EXIT :vfp_thread_exit (thread);break ; + +case THREAD_NOTIFY_COPY : +vfp_thread_copy (thread); +break ; }return NOTIFY_DONE ;