summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-05-25 22:44:19 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-05-25 22:44:19 +0200
commit96511b274de06c994597e45236730fee324fd15f (patch)
tree7506288731db1761e31b0b2069349cb9b115fd6d
parent8b40eecea8905cd70b240df77b0f30814a2adf73 (diff)
kernel: fix floating point exceptions (was broken by sse kernel changes)
the fpenv() instruction stores in x87 format, using mathstate() would interpret fpsave as FPssestate in case it was enabled! instead, pass the status word and fppc explicitely to mathnote() in matherror(). get rid of m->fpsavealign buffer, as we can just use FPssesave struct which has enougth padding so rounding up base pointer will not overflow.
-rw-r--r--sys/src/9/pc/dat.h1
-rw-r--r--sys/src/9/pc/main.c93
2 files changed, 39 insertions, 55 deletions
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h
index 030109433..e8d422414 100644
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -256,7 +256,6 @@ struct Mach
uvlong tscticks;
int pdballoc;
int pdbfree;
- FPsave *fpsavalign;
vlong mtrrcap;
vlong mtrrdef;
diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c
index 6310d3b99..35cfccf01 100644
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -480,36 +480,10 @@ static char* mathmsg[] =
};
static void
-mathstate(ulong *stsp, ulong *pcp, ulong *ctlp)
-{
- ulong sts, fpc, ctl;
- FPsave *f = &up->fpsave;
-
- if(fpsave == fpx87save){
- sts = f->status;
- fpc = f->pc;
- ctl = f->control;
- } else {
- sts = f->fsw;
- fpc = f->fpuip;
- ctl = f->fcw;
- }
- if(stsp)
- *stsp = sts;
- if(pcp)
- *pcp = fpc;
- if(ctlp)
- *ctlp = ctl;
-}
-
-static void
-mathnote(void)
+mathnote(ulong status, ulong pc)
{
- int i;
- ulong status, pc;
char *msg, note[ERRMAX];
-
- mathstate(&status, &pc, nil);
+ int i;
/*
* Some attention should probably be paid here to the
@@ -532,7 +506,7 @@ mathnote(void)
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
- msg, up->fpsave.pc, status);
+ msg, pc, status);
postnote(up, 1, note, NDebug);
}
@@ -540,7 +514,6 @@ mathnote(void)
* sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
* so we shuffle the data up and down as needed or make copies.
*/
-
void
fpssesave(FPsave *fps)
{
@@ -548,7 +521,7 @@ fpssesave(FPsave *fps)
afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
fpssesave0(afps);
- if (fps != afps) /* not aligned? shuffle down from aligned buffer */
+ if(fps != afps) /* not aligned? shuffle down from aligned buffer */
memmove(fps, afps, sizeof(FPssestate) - FPalign);
}
@@ -558,28 +531,46 @@ fpsserestore(FPsave *fps)
FPsave *afps;
afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
- if (fps != afps) {
- if (m->fpsavalign == nil)
- m->fpsavalign = mallocalign(sizeof(FPssestate),
- FPalign, 0, 0);
- if (m->fpsavalign)
- afps = m->fpsavalign;
- /* copy or shuffle up to make aligned */
+ if(fps != afps) /* shuffle up to make aligned */
memmove(afps, fps, sizeof(FPssestate) - FPalign);
- }
fpsserestore0(afps);
- /* if we couldn't make a copy, shuffle regs back down */
- if (fps != afps && afps != m->fpsavalign)
+ if(fps != afps) /* shuffle regs back down when unaligned */
memmove(fps, afps, sizeof(FPssestate) - FPalign);
}
/*
+ * extract control, status and fppc from process
+ * floating point state independent of format.
+ */
+static void
+mathstate(ulong *stsp, ulong *pcp, ulong *ctlp)
+{
+ ulong sts, fpc, ctl;
+ FPsave *f = &up->fpsave;
+
+ if(fpsave == fpx87save){
+ sts = f->status;
+ fpc = f->pc;
+ ctl = f->control;
+ } else {
+ sts = f->fsw;
+ fpc = f->fpuip;
+ ctl = f->fcw;
+ }
+ if(stsp)
+ *stsp = sts;
+ if(pcp)
+ *pcp = fpc;
+ if(ctlp)
+ *ctlp = ctl;
+}
+
+/*
* math coprocessor error
*/
static void
-matherror(Ureg *ur, void*)
+matherror(Ureg*, void*)
{
- ulong status, pc;
/*
* a write cycle to port 0xF0 clears the interrupt latch attached
* to the error# line from the 387
@@ -588,16 +579,10 @@ matherror(Ureg *ur, void*)
outb(0xF0, 0xFF);
/*
- * save floating point state to check out error
+ * get floating point state to check out error
*/
fpenv(&up->fpsave);
- mathnote();
-
- if((ur->pc & 0xf0000000) == KZERO){
- mathstate(&status, &pc, nil);
- panic("fp: status %ux fppc=0x%lux pc=0x%lux",
- up->fpsave.status, up->fpsave.pc, ur->pc);
- }
+ mathnote(up->fpsave.status, up->fpsave.pc);
}
/*
@@ -606,7 +591,7 @@ matherror(Ureg *ur, void*)
static void
mathemu(Ureg *ureg, void*)
{
- ulong status, control;
+ ulong status, control, pc;
if(up->fpstate & FPillegal){
/* someone did floating point in a note handler */
@@ -626,9 +611,9 @@ mathemu(Ureg *ureg, void*)
* More attention should probably be paid here to the
* exception masks and error summary.
*/
- mathstate(&status, nil, &control);
+ mathstate(&status, &pc, &control);
if((status & ~control) & 0x07F){
- mathnote();
+ mathnote(status, pc);
break;
}
fprestore(&up->fpsave);