linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] i386/x86_64 fpu: fix x87 tag word simulation using fxsave
@ 2005-01-17  1:36 Roland McGrath
  2005-01-17  3:48 ` Linus Torvalds
  0 siblings, 1 reply; 3+ messages in thread
From: Roland McGrath @ 2005-01-17  1:36 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds; +Cc: linux-kernel, Dave Jones

Note, this code is identical in 2.4 so this fix applies there as well.


A user reported that the x87 "tag word" value reported by PTRACE_GETFPREGS
did not match what the "fnsave" instruction stores for the same FPU state.
It turns out to be a bug in the conversion from fxsave format to fnsave
format.  (This can also bite interrupted FPU state restored by a signal
handler.)  The tag bits (in both formats) are stored in physical register
order, though the register contents are stored in x87 register stack order.
This is barely mentioned in the processor manuals, and easy to overlook.
It's even more confusing when you read the AMD64 manuals, which erroneously
claim that fxsave stores the register contents in physical order as well.
Fortunately, only the manuals differ and all the chips actually agree.


Signed-off-by: Roland McGrath <roland@redhat.com>

--- linux-2.6/arch/i386/kernel/i387.c
+++ linux-2.6/arch/i386/kernel/i387.c
@@ -111,6 +111,7 @@ static inline unsigned short twd_i387_to
 static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
 {
 	struct _fpxreg *st = NULL;
+	const unsigned int tos = (fxsave->swd >> 11) & 7;
 	unsigned long twd = (unsigned long) fxsave->twd;
 	unsigned long tag;
 	unsigned long ret = 0xffff0000u;
@@ -120,7 +121,10 @@ static inline unsigned long twd_fxsr_to_
 
 	for ( i = 0 ; i < 8 ; i++ ) {
 		if ( twd & 0x1 ) {
-			st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
+			/* The tag bits are saved in physical order,
+			   but the registers are saved in stack order.  */
+			st = (struct _fpxreg *) FPREG_ADDR(fxsave,
+							   (i + 8 - tos) & 7);
 
 			switch ( st->exponent & 0x7fff ) {
 			case 0x7fff:
--- linux-2.6/arch/x86_64/ia32/fpu32.c
+++ linux-2.6/arch/x86_64/ia32/fpu32.c
@@ -28,6 +28,7 @@ static inline unsigned short twd_i387_to
 static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
 {
 	struct _fpxreg *st = NULL;
+	const unsigned int tos = (fxsave->swd >> 11) & 7;
 	unsigned long twd = (unsigned long) fxsave->twd;
 	unsigned long tag;
 	unsigned long ret = 0xffff0000;
@@ -37,7 +38,10 @@ static inline unsigned long twd_fxsr_to_
 
 	for (i = 0 ; i < 8 ; i++) {
 		if (twd & 0x1) {
-			st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
+			/* The tag bits are saved in physical order,
+			   but the registers are saved in stack order.  */
+			st = (struct _fpxreg *) FPREG_ADDR(fxsave,
+							   (i + 8 - tos) & 7);
 
 			switch (st->exponent & 0x7fff) {
 			case 0x7fff:

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-01-17  5:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-01-17  1:36 [PATCH] i386/x86_64 fpu: fix x87 tag word simulation using fxsave Roland McGrath
2005-01-17  3:48 ` Linus Torvalds
2005-01-17  5:47   ` Roland McGrath

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).