[PATCH] i386/x86_64 fpu: fix x87 tag word simulation using fxsave
Linux Kernel Mailing List <[email protected]> Sat, 12 Mar 2005 12:31:25 +0000
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
ChangeSet 1.1575, 2005/03/12 09:31:25-03:00, [email protected] [PATCH] i386/x86_64 fpu: fix x87 tag word simulation using fxsave Fix x87 fnsave Tag Word emulation when using FXSR (SSE) From: Roland McGrath <[email protected]> The fxsave instruction does not save the x87 tag word (only the empty bits), and we re-created the old-style x87 tags incorrectly. The registers are saved in "stack order" in the save area, but the tag word bits are in "hardware order", and we need to get the right register state. Both x86 and x86-64 needed this fix. Signed-off-by: Roland McGrath <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> i386/kernel/i387.c | 5 +++-- x86_64/ia32/fpu32.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff -Nru a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c --- a/arch/i386/kernel/i387.c 2005-03-12 10:03:13 -08:00 +++ b/arch/i386/kernel/i387.c 2005-03-12 10:03:13 -08:00 @@ -128,16 +128,17 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave ) { struct _fpxreg *st = NULL; + unsigned long tos = (fxsave->swd >> 11) & 7; unsigned long twd = (unsigned long) fxsave->twd; unsigned long tag; unsigned long ret = 0xffff0000; int i; -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); +#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16); for ( i = 0 ; i < 8 ; i++ ) { if ( twd & 0x1 ) { - st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); + st = FPREG_ADDR( fxsave, (i - tos) & 7 ); switch ( st->exponent & 0x7fff ) { case 0x7fff: diff -Nru a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c --- a/arch/x86_64/ia32/fpu32.c 2005-03-12 10:03:13 -08:00 +++ b/arch/x86_64/ia32/fpu32.c 2005-03-12 10:03:13 -08:00 @@ -28,16 +28,17 @@ static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) { struct _fpxreg *st = NULL; + unsigned long tos = (fxsave->swd >> 11) & 7; unsigned long twd = (unsigned long) fxsave->twd; unsigned long tag; unsigned long ret = 0xffff0000; int i; -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); +#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16); for (i = 0 ; i < 8 ; i++) { if (twd & 0x1) { - st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); + st = FPREG_ADDR( fxsave, (i - tos) & 7 ); switch (st->exponent & 0x7fff) { case 0x7fff: