Skip to contentSkip to conversation

ARM: vfp: move user vfp state save/restore code out of signal.c

PATCH New Will Deacon 2 participants 9 messages Feb 23, 2012 – May 14, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v4 1/2 ARM: vfp: move user vfp state save/restore code out of signal.c

The user VFP state must be preserved (subject to ucontext modifications) across invocation of a signal handler and this is currently handled by vfp_{preserve,restore}_context in signal.c

Since this code requires intimate low-level knowledge of the VFP state, this patch moves it into vfpmodule.c.

---

v4: minor naming changes to appease Dave's dislike of the old ones.

 arch/arm/include/asm/thread_info.h |    7 +++
 arch/arm/kernel/signal.c           |   57 ++-----------------------
 arch/arm/vfp/vfpmodule.c           |   79 ++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 52 deletions(-)
arch/arm/include/asm/thread_info.h +7 -0
index d4c24d4..0f04d84 100644
@@ -118,6 +118,13 @@ extern void iwmmxt_task_switch(struct thread_info *);
 extern void vfp_sync_hwstate(struct thread_info *);
 extern void vfp_flush_hwstate(struct thread_info *);
 
+struct user_vfp;
+struct user_vfp_exc;
+
+extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
+					   struct user_vfp_exc __user *);
+extern int vfp_restore_user_hwstate(struct user_vfp __user *,
+				    struct user_vfp_exc __user *);
 #endif
 
 /*
arch/arm/kernel/signal.c +4 -51

81 lines not on this page · raw message

arch/arm/vfp/vfpmodule.c +79 -0

91 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#1 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

The ARM PCS mandates that the length and stride bits of the fpscr are cleared on entry to and return from a public interface. Although signal handlers run asynchronously with respect to the interrupted function, the handler itself expects to run as though it has been called like a normal function.

This patch updates the state mirroring the VFP hardware before entry to a signal handler so that it adheres to the PCS. Furthermore, we disable VFP to ensure that we trap on any floating point operation performed by the signal handler and synchronise the hardware appropriately. A check is inserted after the signal handler to avoid redundant flushing if VFP was not used.

---
 arch/arm/vfp/vfpmodule.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)
arch/arm/vfp/vfpmodule.c +21 -1
index 1dfe7d8..269f40d 100644
@@ -562,6 +562,21 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
 
 	if (err)
 		return -EFAULT;
+
+	/* Ensure that VFP is disabled. */
+	vfp_flush_hwstate(thread);
+
+	/*
+	 * As per the PCS, clear the length and stride bits for function
+	 * entry.
+	 */
+	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
+
+	/*
+	 * Disable VFP in the hwstate so that we can detect if it gets
+	 * used.
+	 */
+	hwstate->fpexc &= ~FPEXC_EN;
 	return 0;
 }
 
@@ -574,7 +589,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 
-	vfp_flush_hwstate(thread);
+	/*
+	 * If VFP has been used, then disable it to avoid corrupting
+	 * the new thread state.
+	 */
+	if (hwstate->fpexc & FPEXC_EN)
+		vfp_flush_hwstate(thread);
 
 	/*
 	 * Copy the floating point registers. There can be unused
Signature · 1 line
1.7.4.1
#2 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Hi Will

I've bisected a screen corruption problem on vexpress down to this commit, I've commented at the end of the patch at to what I see the problem being...

Quoted 49 lines · Will Deacon

The ARM PCS mandates that the length and stride bits of the fpscr are cleared on entry to and return from a public interface. Although signal handlers run asynchronously with respect to the interrupted function, the handler itself expects to run as though it has been called like a normal function.

This patch updates the state mirroring the VFP hardware before entry to a signal handler so that it adheres to the PCS. Furthermore, we disable VFP to ensure that we trap on any floating point operation performed by the signal handler and synchronise the hardware appropriately. A check is inserted after the signal handler to avoid redundant flushing if VFP was not used.

---
 arch/arm/vfp/vfpmodule.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)
arch/arm/vfp/vfpmodule.c +15 -0
index 1dfe7d8..269f40d 100644
@@ -562,6 +562,21 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
 
 	if (err)
 		return -EFAULT;
+
+	/* Ensure that VFP is disabled. */
+	vfp_flush_hwstate(thread);
+
+	/*
+	 * As per the PCS, clear the length and stride bits for function
+	 * entry.
+	 */
+	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
+
+	/*
+	 * Disable VFP in the hwstate so that we can detect if it gets
+	 * used.
+	 */
+	hwstate->fpexc &= ~FPEXC_EN;
 	return 0;
 }
 
@@ -574,7 +589,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 

arch/arm/vfp/vfpmodule.c int vfp_restore_user_hwstate(struct user_vfp __user *ufp, · line 600

Quoted 10 lines
arch/arm/vfp/vfpmodule.c +6 -1
-	vfp_flush_hwstate(thread);
+	/*
+	 * If VFP has been used, then disable it to avoid corrupting
+	 * the new thread state.
+	 */
+	if (hwstate->fpexc & FPEXC_EN)
+		vfp_flush_hwstate(thread);
 
 	/*
 	 * Copy the floating point registers. There can be unused

If the signal handler uses VFP, will it actually cause hwstate->fpexc & FPEXC_EN to be set? Won't it instead just enable the VFP in the hardware registers? (It looks to me that hwstate only gets updated by vfp_flush_hwstate().)

This certainly seems to be the case in my screen corruption situation where on entry to vfp_restore_user_hwstate() "fmrx(FPEXC) & FPEXC_EN" is true and "hwstate->fpexc & FPEXC_EN" is false.

With the code as it stands this means that on return from a signal handler the vfp hardware registers will be in whatever state the signal handler left them in, not the thread's state at the point the signal happened.

Assuming that I have understood things correctly, then I plan on posting a patch that would make code changes like...

arch/arm/vfp/vfpmodule.c +0 -0
index bc683b8..386a81a 100644
@@ -574,11 +574,6 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp

__user *ufp,

         */
        hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);

- /*

-        * Disable VFP in the hwstate so that we can detect if it gets
-        * used.
-        */
-       hwstate->fpexc &= ~FPEXC_EN;
        return 0;

}

@@ -591,12 +586,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,

        unsigned long fpexc;
        int err = 0;

- /*

-        * If VFP has been used, then disable it to avoid corrupting
-        * the new thread state.
-        */

- if (hwstate->fpexc & FPEXC_EN)
- vfp_flush_hwstate(thread);
+ vfp_flush_hwstate(thread);

/*
* Copy the floating point registers. There can be unused

Signature · 1 line
Tixy 
#3 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Quoted 1 line · Jon Medhurst (Tixy)

Hi Will

Hi Jon,

Quoted 3 lines

I've bisected a screen corruption problem on vexpress down to this commit, I've commented at the end of the patch at to what I see the problem being...

Interesting and thanks for the heads up. I've been running with this patch applied for ages and haven't seen any problems myself but I've also been running headless. What's the best way to reproduce the problem on vexpress? I can connect a display if required.

Quoted 13 lines · Will Deacon
Quoted 12 lines
(quoted diff) +6 -1
@@ -574,7 +589,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 
-	vfp_flush_hwstate(thread);
+	/*
+	 * If VFP has been used, then disable it to avoid corrupting
+	 * the new thread state.
+	 */
+	if (hwstate->fpexc & FPEXC_EN)
+		vfp_flush_hwstate(thread);
 
Quoted 7 lines

Review int vfp_restore_user_hwstate(struct user_vfp __user *ufp, · line 600

Quoted 2 lines
(quoted diff) +0 -0
 	/*
 	 * Copy the floating point registers. There can be unused

If the signal handler uses VFP, will it actually cause hwstate->fpexc & FPEXC_EN to be set? Won't it instead just enable the VFP in the hardware registers? (It looks to me that hwstate only gets updated by vfp_flush_hwstate().)

The idea is that we disable VFP in hardware (via vfp_flush_hwstate) prior to entering the signal handler. Then we clear hwstate->fpexc.FPEXC_EN so that we can detect if VFP gets used during the handler, since the exception handling code will set that back up if we trapon a VFP operation (see vfp_support_entry in vfphw.S).

Quoted 3 lines

This certainly seems to be the case in my screen corruption situation where on entry to vfp_restore_user_hwstate() "fmrx(FPEXC) & FPEXC_EN" is true and "hwstate->fpexc & FPEXC_EN" is false.

That sounds wrong to me. Out of interest, can you try this patch please?:

http://git.kernel.org/?p=linux/kernel/git/will/linux.git;a=commit;h=468c963e0210bf8108b17cf75066f25f39cabb56

Of course, if you're not running with CONFIG_PREEMPT, that shouldn't make a difference.

Quoted 4 lines

With the code as it stands this means that on return from a signal handler the vfp hardware registers will be in whatever state the signal handler left them in, not the thread's state at the point the signal happened.

That shouldn't happen -- what we need to figure out is why your previous paragraph is occurring.

Cheers,

Will

#4 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Quoted 9 lines · Will Deacon
Quoted 3 lines · Jon Medhurst (Tixy)

I've bisected a screen corruption problem on vexpress down to this commit, I've commented at the end of the patch at to what I see the problem being...

Interesting and thanks for the heads up. I've been running with this patch applied for ages and haven't seen any problems myself but I've also been running headless. What's the best way to reproduce the problem on vexpress? I can connect a display if required.

Right, I've managed to trigger it on my board with lxdm, so I'll dig further and let you know. The patch I posted doesn't help, so don't waste time applying it.

Cheers,

Will

#5 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

In reply to Will Deacon
Quoted 5 lines · Will Deacon
Quoted 1 line · Jon Medhurst (Tixy)

Hi Will

Hi Jon,

Quoted 8 lines
Quoted 3 lines

I've bisected a screen corruption problem on vexpress down to this commit, I've commented at the end of the patch at to what I see the problem being...

Interesting and thanks for the heads up. I've been running with this patch applied for ages and haven't seen any problems myself but I've also been running headless. What's the best way to reproduce the problem on vexpress? I can connect a display if required.

I'm running the Ubuntu Desktop image from Linaro's last release [1] but with the kernel uImage replaced by one I built based on rc6 + one MMC hack [2]. Once booted as far as the yellow wallpaper then moving the mouse around the screen causes black streaks of pixels to be left of the screen.

Quoted 21 lines
Quoted 13 lines · Will Deacon
Quoted 12 lines
(quoted diff) +6 -1
@@ -574,7 +589,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 
-	vfp_flush_hwstate(thread);
+	/*
+	 * If VFP has been used, then disable it to avoid corrupting
+	 * the new thread state.
+	 */
+	if (hwstate->fpexc & FPEXC_EN)
+		vfp_flush_hwstate(thread);
 
Quoted 7 lines

Review int vfp_restore_user_hwstate(struct user_vfp __user *ufp, · line 600

Quoted 2 lines
(quoted diff) +0 -0
 	/*
 	 * Copy the floating point registers. There can be unused

If the signal handler uses VFP, will it actually cause hwstate->fpexc & FPEXC_EN to be set? Won't it instead just enable the VFP in the hardware registers? (It looks to me that hwstate only gets updated by vfp_flush_hwstate().)

Quoted 5 lines

The idea is that we disable VFP in hardware (via vfp_flush_hwstate) prior to entering the signal handler. Then we clear hwstate->fpexc.FPEXC_EN so that we can detect if VFP gets used during the handler, since the exception handling code will set that back up if we trapon a VFP operation (see vfp_support_entry in vfphw.S).

I had a look at vfp_support_entry. I can see it loading the hardware registers from the saved vfp state, but can't see where it updates the fpexc value in the saved vfp state. (I also can't think of why it would need to, but this is the first time I've looked Linux vfp code so there could be lots I've missed.)

Quoted 10 lines
Quoted 3 lines

This certainly seems to be the case in my screen corruption situation where on entry to vfp_restore_user_hwstate() "fmrx(FPEXC) & FPEXC_EN" is true and "hwstate->fpexc & FPEXC_EN" is false.

That sounds wrong to me. Out of interest, can you try this patch please?:

http://git.kernel.org/?p=linux/kernel/git/will/linux.git;a=commit;h=468c963e0210bf8108b17cf75066f25f39cabb56

Of course, if you're not running with CONFIG_PREEMPT, that shouldn't make a difference.

I'm not, and it didn't. :-)

Signature · 4 lines
Tixy

[1] http://releases.linaro.org/12.04/ubuntu/vexpress/
[2] http://git.linaro.org/gitweb?p=people/tixy/kernel.git;a=shortlog;h=refs/heads/vfp-regs-bug
#6 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Quoted 7 lines · Jon Medhurst (Tixy)
Quoted 5 lines · Will Deacon

The idea is that we disable VFP in hardware (via vfp_flush_hwstate) prior to entering the signal handler. Then we clear hwstate->fpexc.FPEXC_EN so that we can detect if VFP gets used during the handler, since the exception handling code will set that back up if we trapon a VFP operation (see vfp_support_entry in vfphw.S).

Quoted 5 lines

I had a look at vfp_support_entry. I can see it loading the hardware registers from the saved vfp state, but can't see where it updates the fpexc value in the saved vfp state. (I also can't think of why it would need to, but this is the first time I've looked Linux vfp code so there could be lots I've missed.)

You're right, in the lazy case (i.e. SMP) we update the hwstate on context-switch rather than on the fault. Your quick fix looks good to me (that is, unconditionally flushing the state after handling a signal). I was initially worried that the added flushing would cause a performance hit on the usual path, where VFP is not used in the handler, however since we flush before the signal handler, it really won't make a lot of difference.

I took the liberty of writing a commit message, so can I add your S-o-B to this please (I wasn't sure which email address to use)?

Thanks,

Will

Subject: [PATCH] ARM: vfp: fix VFP flushing regression on sigreturn path

Commit ff9a184c ("ARM: 7400/1: vfp: clear fpscr length and stride bits on entry to sig handler") flushes the VFP state prior to entering a signal handler so that a VFP operation inside the handler will trap and force a restore of ABI-compliant registers. Restoring the registers on the sigreturn path is predicated on the saved thread state indicating that VFP was used by the handler -- however for SMP platforms this is only set on context-switch, making the check unreliable and causing VFP register corruption in userspace.

This patch unconditionally flushes the VFP state after a signal handler. Since we already perform the flush before the handler and the flushing itself happens lazily, the effect on performance is negligible.

---
 arch/arm/vfp/vfpmodule.c |   14 ++------------
 1 files changed, 2 insertions(+), 12 deletions(-)
arch/arm/vfp/vfpmodule.c +2 -12
index c5767b5..b0197b2 100644
@@ -577,12 +577,6 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
 	 * entry.
 	 */
 	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
-
-	/*
-	 * Disable VFP in the hwstate so that we can detect if it gets
-	 * used.
-	 */
-	hwstate->fpexc &= ~FPEXC_EN;
 	return 0;
 }
 
@@ -595,12 +589,8 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 
-	/*
-	 * If VFP has been used, then disable it to avoid corrupting
-	 * the new thread state.
-	 */
-	if (hwstate->fpexc & FPEXC_EN)
-		vfp_flush_hwstate(thread);
+	/* Disable VFP to avoid corrupting the new thread state. */
+	vfp_flush_hwstate(thread);
 
 	/*
 	 * Copy the floating point registers. There can be unused
Signature · 1 line
1.7.4.1
#7 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Quoted 9 lines · Will Deacon

You're right, in the lazy case (i.e. SMP) we update the hwstate on context-switch rather than on the fault. Your quick fix looks good to me (that is, unconditionally flushing the state after handling a signal). I was initially worried that the added flushing would cause a performance hit on the usual path, where VFP is not used in the handler, however since we flush before the signal handler, it really won't make a lot of difference.

I took the liberty of writing a commit message, so can I add your S-o-B to this please (I wasn't sure which email address to use)?

Thanks, it's the day job, so...

Quoted 57 lines

Thanks,

Will

Subject: [PATCH] ARM: vfp: fix VFP flushing regression on sigreturn path

Commit ff9a184c ("ARM: 7400/1: vfp: clear fpscr length and stride bits on entry to sig handler") flushes the VFP state prior to entering a signal handler so that a VFP operation inside the handler will trap and force a restore of ABI-compliant registers. Restoring the registers on the sigreturn path is predicated on the saved thread state indicating that VFP was used by the handler -- however for SMP platforms this is only set on context-switch, making the check unreliable and causing VFP register corruption in userspace.

This patch unconditionally flushes the VFP state after a signal handler. Since we already perform the flush before the handler and the flushing itself happens lazily, the effect on performance is negligible.

---
 arch/arm/vfp/vfpmodule.c |   14 ++------------
 1 files changed, 2 insertions(+), 12 deletions(-)
arch/arm/vfp/vfpmodule.c +2 -12
index c5767b5..b0197b2 100644
@@ -577,12 +577,6 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
 	 * entry.
 	 */
 	hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
-
-	/*
-	 * Disable VFP in the hwstate so that we can detect if it gets
-	 * used.
-	 */
-	hwstate->fpexc &= ~FPEXC_EN;
 	return 0;
 }
 
@@ -595,12 +589,8 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
 	unsigned long fpexc;
 	int err = 0;
 
-	/*
-	 * If VFP has been used, then disable it to avoid corrupting
-	 * the new thread state.
-	 */
-	if (hwstate->fpexc & FPEXC_EN)
-		vfp_flush_hwstate(thread);
+	/* Disable VFP to avoid corrupting the new thread state. */
+	vfp_flush_hwstate(thread);
 
 	/*
 	 * Copy the floating point registers. There can be unused
#8 lore raw

PATCH v4 2/2 ARM: vfp: clear fpscr length and stride bits on entry to sig handler

Quoted 8 lines · Jon Medhurst (Tixy)
Quoted 7 lines · Will Deacon

You're right, in the lazy case (i.e. SMP) we update the hwstate on context-switch rather than on the fault. Your quick fix looks good to me (that is, unconditionally flushing the state after handling a signal). I was initially worried that the added flushing would cause a performance hit on the usual path, where VFP is not used in the handler, however since we flush before the signal handler, it really won't make a lot of difference.

Quoted 6 lines
Quoted 2 lines

I took the liberty of writing a commit message, so can I add your S-o-B to this please (I wasn't sure which email address to use)?

Thanks, it's the day job, so...

Cheers Jon, I'll stick this in the patch system tomorrow. If it doesn't make the final cut, I'll retrospectively send it to stable when they move to 3.4.

Will