From ca597059f8c66dc96f5830b11f0619dffbb3eacc Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sun, 26 Jul 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-07-26 --- gnot/mem.h | 1 - pc/mem.h | 1 - port/alloc.c | 2 +- port/portdat.h | 1 + power/mem.h | 1 - ss/dat.h | 7 +- ss/fns.h | 7 +- ss/fptrap.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++ ss/l.s | 42 ++++++++-- ss/trap.c | 41 +++++++-- 10 files changed, 303 insertions(+), 23 deletions(-) create mode 100644 ss/fptrap.c diff --git a/gnot/mem.h b/gnot/mem.h index 0d6523f01e44863e169c83f9beb202a9cf4d1769..fef61b8028c16b44d7f2ee90f2c02b379a3a0f3b 100644 --- a/gnot/mem.h +++ b/gnot/mem.h @@ -15,7 +15,6 @@ #define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) #define ICACHESIZE 0 #define MB4 (4*1024*1024) /* Lots of things are 4Mb in size */ -#define MB (1024*1024) #define MAXMACH 1 /* max # cpus system can run */ diff --git a/pc/mem.h b/pc/mem.h index f79cc370887f213c561103462f08babad2d90417..78ed71ece5fc33c4d0dbb33ecaff4c9fbe14c5e6 100644 --- a/pc/mem.h +++ b/pc/mem.h @@ -12,7 +12,6 @@ #define WD2PG (BY2PG/BY2WD) /* words per page */ #define PGSHIFT 12 /* log(BY2PG) */ #define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) -#define MB (1024*1024) #define MAXMACH 1 /* max # cpus system can run */ diff --git a/port/alloc.c b/port/alloc.c index 513312322d2e32d68d37a919b5eaaca59e6bc5fd..e1a1d153b0ef5e76a33b32ba9ec65f6b775dcbc5 100644 --- a/port/alloc.c +++ b/port/alloc.c @@ -113,7 +113,7 @@ xinit(void) palloc.np0 = np0; palloc.np1 = np1; - /* Save the bounds of kernel alloc memory for kernel mmu mapping (NeXT) */ + /* Save the bounds of kernel alloc memory for kernel mmu mapping */ conf.base0 = (ulong)KADDR(conf.base0); conf.base1 = (ulong)KADDR(conf.base1); conf.npage0 = (ulong)KADDR(conf.npage0); diff --git a/port/portdat.h b/port/portdat.h index 41884123d7a68e04c08d4028d17ec8a40bdec0ac..64b3d362a988e22acb634a3573029164046b52af 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -676,6 +676,7 @@ struct Network #define PRINTSIZE 256 #define NUMSIZE 12 /* size of formatted number */ +#define MB (1024*1024) extern Conf conf; extern char* conffile; diff --git a/power/mem.h b/power/mem.h index dc8aa655f246d43353b4d53b44429a821de717e4..63d80fe332fea63ea89a8aaee2f9091082cc2f15 100644 --- a/power/mem.h +++ b/power/mem.h @@ -14,7 +14,6 @@ #define PGSHIFT 12 /* log(BY2PG) */ #define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) #define ICACHESIZE (64*1024) /* Power series */ -#define MB (1024*1024) #define MAXMACH 4 /* max # cpus system can run */ diff --git a/ss/dat.h b/ss/dat.h index 06f4e6bd2c3bec92021945e0fd573700e3333b5e..50fca1904f541186212b2e3bf57c5340dbe48434 100644 --- a/ss/dat.h +++ b/ss/dat.h @@ -48,11 +48,16 @@ enum FPinactive, }; +#define NFPQ 4 /* just a guess */ + struct FPsave { long fsr; long fpreg[32]; - long pad; /* so fsr can be guaranteed at 4 mod 8 */ + struct{ + ulong a; /* address */ + ulong i; /* instruction */ + }q[NFPQ]; }; struct Conf diff --git a/ss/fns.h b/ss/fns.h index d705323008b8376f1a27ce20f3f28c0ab841dc67..66bbc36198437789a6127b86066d2c2da5fd35ef 100644 --- a/ss/fns.h +++ b/ss/fns.h @@ -1,9 +1,11 @@ #include "../port/portfns.h" void cacheinit(void); -void clearfpintr(void); +void clearftt(ulong); #define clearmmucache() void clockinit(void); +void disabfp(void); +void enabfp(void); void evenaddr(ulong); char* excname(ulong); void faultasync(Ureg*); @@ -15,7 +17,10 @@ void fpregrestore(char*); void fpregsave(char*); void fprestore(FPsave*); void fpsave(FPsave*); +int fptrap(void); int getb2(ulong); +int getfpq(ulong*); +ulong getfsr(void); int getw2(ulong); void intrinit(void); void ioinit(void); diff --git a/ss/fptrap.c b/ss/fptrap.c new file mode 100644 index 0000000000000000000000000000000000000000..92378cb9166d1453b86ba2e0afdc23119260b00e --- /dev/null +++ b/ss/fptrap.c @@ -0,0 +1,223 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "io.h" +#include "../port/error.h" + +static int unfinished(FPsave*); +static int fixq(FPsave*, int); +extern void* bbmalloc(int); + +int +fptrap(void) +{ + int n, ret; + ulong fsr; + + n = getfpq(&u->fpsave.q[0].a); + if(n > NFPQ) + panic("FPQ %d\n", n); + again: + fsr = getfsr(); + savefpregs(&u->fpsave); + u->fpsave.fsr = fsr; + ret = 0; + switch((fsr>>14) & 7){ + case 2: + ret = unfinished(&u->fpsave); + break; + } + if(ret){ + enabfp(); /* savefpregs disables it */ + clearftt(fsr & ~0x1F); /* clear ftt and cexc */ + restfpregs(&u->fpsave); + enabfp(); /* restfpregs disables it */ + n = fixq(&u->fpsave, n); + if(n > 0) + goto again; + } + return ret; +} + +static void +unpack(FPsave *f, int size, int reg, int *sign, int *exp) +{ + *sign = 1; + if(f->fpreg[reg] & 0x80000000) + *sign = -1; + switch(size){ + case 1: + *exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2); + break; + case 2: + if(reg & 1){ + pprint("unaligned double fp register\n"); + reg &= ~1; + } + *exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2); + break; + case 3: + if(reg & 3){ + pprint("unaligned quad fp register\n"); + reg &= ~3; + } + *exp = ((f->fpreg[reg]>>16)&0x7FFF) - ((1<<14)-2); + break; + } +} + +static void +zeroreg(FPsave *f, int size, int reg, int sign) +{ + switch(size){ + case 1: + size = 4; + break; + case 2: + if(reg & 1) + reg &= ~1; + size = 8; + break; + case 3: + if(reg & 3) + reg &= ~3; + size = 16; + break; + } + memset(&f->fpreg[reg], 0, size); + if(sign < 0) + f->fpreg[reg] |= 0x80000000; +} + +static int +unfinished(FPsave *f) +{ + ulong instr; + int size, maxe, maxm, op, rd, rs1, rs2; + int sd, ss1, ss2; + int ed, es1, es2; + + instr = f->q[0].i; + if((instr&0xC1F80000) != 0x81A00000){ + bad: + pprint("unknown unfinished instruction %lux\n", instr); + return 0; + } + size = (instr>>5) & 0x3; + if(size == 0) + goto bad; + maxe = 0; + maxm = 0; + switch(size){ + case 1: + maxe = 1<<7; + maxm = 24; + break; + case 2: + maxe = 1<<10; + maxm = 53; + break; + case 3: + maxe = 1<<14; + maxm = 113; + break; + } + rd = (instr>>25) & 0x1F; + rs1 = (instr>>14) & 0x1F; + rs2 = (instr>>0) & 0x1F; + unpack(f, size, rs1, &ss1, &es1); + unpack(f, size, rs2, &ss2, &es2); + op = (instr>>7) & 0x7F; + ed = 0; + switch(op){ + case 0x11: /* FSUB */ + ss2 = -ss2; + case 0x10: /* FADD */ + if(es1<-(maxe-maxm) && es2<-(maxe-maxm)) + ed = -maxe; + if(es1 > es2) + sd = es1; + else + sd = es2; + break; + + case 0x13: /* FDIV */ + es2 = -es2; + case 0x12: /* FMUL */ + sd = 1; + if(ss1 != ss2) + sd = -1; + ed = es1 + es2; + break; + + case 0x31: /* F?TOS */ + case 0x32: /* F?TOD */ + case 0x33: /* F?TOQ */ + if(es2 == maxe) /* NaN or Inf */ + return 0; + sd = ss2; + ed = es2; /* if underflow, this will do the trick */ + break; + + default: + goto bad; + } + if(ed <= -(maxe-4)){ /* guess: underflow */ + zeroreg(f, size, rd, sd); + return 1; + } + return 0; +} + +static int +fixq(FPsave *f, int n) +{ + ulong instr, fsr; + ulong *ip; + + while(n > 1){ + memmove(&f->q[0], &f->q[1], (n-1)*sizeof f->q[0]); + instr = f->q[0].i; + ip = bbmalloc(3*sizeof(ulong)); + ip[0] = instr; + ip[1] = 0x81c3e008; /* JMPL #8(R15), R0 [RETURN] */ + ip[2] = 0x01000000; /* SETHI #0, R0 [NOP] */ + (*(void(*)(void))ip)(); + /* + * WARNING: This code is wrong (and I don't know how + * to fix it without emulating the entire FPU in + * software--please let me knw) if the queued + * instruction gets an exception: the getfsr() generates + * a trap and the staggeringly inept SPARC design + * translates that to a reset, as you can't have + * nested exceptions. So here's the fairly solid but + * not fail-safe solution: jump out NOW if there's + * nothing else pending. If this last instruction + * causes an exception, it will fire when the *user* + * executes the next FP instruction. The system + * avoids executing any FP on the way out. The + * user will trap and we'll be back but will have + * made progress. The FQ will point to kernel space + * but the trap will happen in user space, and that's + * what matters. + * + * This same botch may cause the system to reset + * if a trap is pending when we call savefpregs() in + * trap.c. I don't know; the documentation is unclear. + */ + if(n == 1) + return 0; + for(;;){ + fsr = getfsr(); + if((fsr & (1<<13)) == 0) /* qne */ + break; + if(fsr & 0x1F) /* cexc */ + return n; + } + --n; + } + return 0; +} diff --git a/ss/l.s b/ss/l.s index 79cf2caf6ecaca9e7b65c3dc6f976c233ae4f6f2..e83ecbe0d67e1c41d62e9dc77f209baccf36371a 100644 --- a/ss/l.s +++ b/ss/l.s @@ -500,6 +500,20 @@ TEXT savefpregs(SB), $0 MOVW R8, PSR RETURN +TEXT enabfp(SB), $0 + + MOVW PSR, R8 + OR $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT disabfp(SB), $0 + + MOVW PSR, R8 + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + TEXT restfpregs(SB), $0 MOVW PSR, R8 @@ -533,17 +547,21 @@ TEXT restfpregs(SB), $0 MOVW R8, PSR RETURN -TEXT clearfpintr(SB), $0 +TEXT getfpq(SB), $0 - MOVW $fpq+BY2WD(SB), R7 - ANDN $0x7, R7 /* must be D aligned */ + MOVW R7, R8 /* must be D aligned */ MOVW $fsr+0(SB), R9 -clrq: - MOVD FQ, (R7) + MOVW $0, R7 +getfpq1: MOVW FSR, (R9) - MOVW (R9), R8 - AND $(1<<13), R8 /* queue not empty? */ - BNE clrq + MOVW (R9), R10 + ANDCC $(1<<13), R10 /* queue not empty? */ + BE getfpq2 + MOVD FQ, (R8) + ADD $1, R7 + ADD $8, R8 + BA getfpq1 +getfpq2: RETURN TEXT getfsr(SB), $0 @@ -552,6 +570,12 @@ TEXT getfsr(SB), $0 MOVW (R7), R7 RETURN +TEXT clearftt(SB), $0 + MOVW R7, fsr+0(SB) + MOVW $fsr+0(SB), R7 + MOVW (R7), FSR + FMOVF F0, F0 + RETURN + GLOBL mach0+0(SB), $MACHSIZE -GLOBL fpq+0(SB), $(3*BY2WD) GLOBL fsr+0(SB), $BY2WD diff --git a/ss/trap.c b/ss/trap.c index b8ecf594324ed05054539a9eae1870c7aaa7be1f..44752d328f22718411cb350218ed2d1fe6f9708b 100644 --- a/ss/trap.c +++ b/ss/trap.c @@ -14,7 +14,8 @@ int domuldiv(ulong, Ureg*); extern void traplink(void); extern void syslink(void); -long ticks; + long ticks; +static char excbuf[64]; /* BUG: not reentrant! */ char *trapname[]={ "reset", @@ -31,14 +32,37 @@ char *trapname[]={ "watchpoint detected", }; +char *fptrapname[]={ + "none", + "IEEE 754 exception", + "unfinished FP op", + "unimplemented FP op", + "sequence error", + "hardware error", + "invalid FP register", + "reserved", +}; + char* excname(ulong tbr) { - static char buf[64]; /* BUG: not reentrant! */ char xx[64]; char *t; + ulong fsr; switch(tbr){ + case 8: + if(u == 0){ + fsr = getfsr(); + sprint(excbuf, "fp: %s FSR %lux", + fptrapname[(fsr>>14)&7], fsr); + }else{ + fsr = u->fpsave.fsr; + sprint(excbuf, "fp: %s FQpc=0x%lux", + fptrapname[(fsr>>14)&7], + u->fpsave.q[0].a, fsr); + } + return excbuf; case 36: return "trap: cp disabled"; case 37: @@ -65,10 +89,10 @@ excname(ulong tbr) t = xx; } if(strncmp(t, "fp: ", 4) == 0) - strcpy(buf, t); + strcpy(excbuf, t); else - sprint(buf, "trap: %s", t); - return buf; + sprint(excbuf, "trap: %s", t); + return excbuf; } void @@ -148,7 +172,10 @@ trap(Ureg *ur) } break; case 8: /* floating point exception */ - clearfpintr(); + if(fptrap()){ + /* do NOT talk to the FPU: see fptrap.c */ + return; + } break; default: break; @@ -157,8 +184,6 @@ trap(Ureg *ur) if(user){ spllo(); sprint(buf, "sys: %s", excname(tbr)); - if(tbr == 8) - sprint(buf+strlen(buf), " FSR %lux", u->fpsave.fsr); postnote(u->p, 1, buf, NDebug); }else{ print("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc);