1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "ureg.h" 7 #include "io.h" 8 #include "../port/error.h" 9 10 void noted(Ureg**, ulong); 11 void rfnote(Ureg**); 12 int domuldiv(ulong, Ureg*); 13 14 extern Label catch; 15 extern void traplink(void); 16 extern void syslink(void); 17 static void faultsparc(Ureg *ur); 18 static void faultasync(Ureg *ur); 19 20 long ticks; 21 static char excbuf[64]; /* BUG: not reentrant! */ 22 23 char *trapname[]={ 24 "reset", 25 "instruction access exception", 26 "illegal instruction", 27 "privileged instruction", 28 "fp: disabled", 29 "window overflow", 30 "window underflow", 31 "unaligned address", 32 "fp: exception", 33 "data access exception", 34 "tag overflow", 35 "watchpoint detected", 36 }; 37 38 char *fptrapname[]={ 39 "none", 40 "IEEE 754 exception", 41 "unfinished FP op", 42 "unimplemented FP op", 43 "sequence error", 44 "hardware error", 45 "invalid FP register", 46 "reserved", 47 } 48 ; 49 50 char* 51 excname(ulong tbr) 52 { 53 char xx[64]; 54 char *t; 55 56 switch(tbr){ 57 case 8: 58 if(up == 0) 59 panic("fptrap in kernel\n"); 60 else{ 61 panic("fptrap not implemented\n"); 62 #ifdef notdef 63 if(m->fpunsafe==0 && up->p->fpstate!=FPactive) 64 panic("fptrap not active\n"); fsr = up->fpsave.env; 65 sprint(excbuf, "fp: %s fppc=0x%lux", 66 fptrapname[(fsr>>14)&7], 67 up->fpsave.q[0].a, fsr); 68 #endif 69 } 70 return excbuf; 71 case 36: 72 return "trap: cp disabled"; 73 case 37: 74 return "trap: unimplemented instruction"; 75 case 40: 76 return "trap: cp exception"; 77 case 42: 78 return "trap: divide by zero"; 79 case 128: 80 return "syscall"; 81 case 129: 82 return "breakpoint"; 83 } 84 t = 0; 85 if(tbr < sizeof trapname/sizeof(char*)) 86 t = trapname[tbr]; 87 if(t == 0){ 88 if(tbr >= 130) 89 sprint(xx, "trap instruction %ld", tbr-128); 90 else if(17<=tbr && tbr<=31) 91 sprint(xx, "interrupt level %ld", tbr-16); 92 else 93 sprint(xx, "unknown trap %ld", tbr); 94 t = xx; 95 } 96 if(strncmp(t, "fp: ", 4) == 0) 97 strcpy(excbuf, t); 98 else 99 sprint(excbuf, "trap: %s", t); 100 return excbuf; 101 102 } 103 104 void 105 trap(Ureg *ur) 106 { 107 int user; 108 ulong tbr, iw; 109 110 tbr = (ur->tbr&0xFFF)>>4; 111 /* 112 * Hack to catch bootstrap fault during probe 113 */ 114 if(catch.pc) 115 gotolabel(&catch); 116 117 if(up) 118 up->dbgreg = ur; 119 120 user = !(ur->psr&PSRPSUPER); 121 if(user) { 122 panic("how did we get to user mode???"); 123 } 124 if(tbr > 16){ /* interrupt */ 125 switch(tbr-16) { 126 case 15: /* asynch mem err */ 127 faultasync(ur); 128 break; 129 case 14: /* processor counter */ 130 clock(ur); 131 break; 132 case 13: /* keyboard/mouse */ 133 ns16552intr(0); 134 kbdintr(); 135 break; 136 case 6: /* lance */ 137 lanceintr(); 138 break; 139 default: 140 print("unexp intr lev %ld\n", tbr-16); 141 goto Error; 142 } 143 }else{ 144 switch(tbr){ 145 case 1: /* instr. access */ 146 case 9: /* data access */ 147 if(up && up->fpstate==FPACTIVE) { 148 fpquiet(); 149 fpsave(&up->fpsave); 150 up->fpstate = FPINACTIVE; 151 } 152 faultsparc(ur); 153 goto Return; 154 case 2: /* illegal instr, maybe mul */ 155 iw = *(ulong*)ur->pc; 156 if((iw&0xC1500000) == 0x80500000){ 157 if(domuldiv(iw, ur)) 158 goto Return; 159 tbr = ur->tbr; 160 } 161 break; 162 case 4: /* floating point disabled */ 163 panic("some more floating point crapola"); 164 break; 165 #ifdef notdef 166 if(u && u->p){ 167 if(up->p->fpstate == FPINIT) 168 restfpregs(initfpp, up->fpsave.fsr); 169 else if(u->p->fpstate == FPinactive) 170 restfpregs(&u->fpsave, u->fpsave.fsr); 171 else 172 break; 173 u->p->fpstate = FPactive; 174 ur->psr |= PSREF; 175 return; 176 } 177 break; 178 #endif 179 case 8: /* floating point exception */ 180 panic("floating point crapola #3"); 181 break; 182 #ifdef notdef 183 /* if unsafe, trap happened shutting down FPU; just return */ 184 if(m->fpunsafe){ 185 m->fptrap = (fptrap()==0); 186 return; 187 } 188 if(fptrap()) 189 goto Return; /* handled the problem */ 190 break; 191 #endif 192 default: 193 break; 194 } 195 Error: 196 panic("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc); 197 } 198 Return: 199 return; 200 } 201 202 void 203 trapinit(void) 204 { 205 int i; 206 long t, a; 207 208 a = ((ulong)traplink-TRAPS)>>2; 209 a += 0x40000000; /* CALL traplink(SB) */ 210 t = TRAPS; 211 for(i=0; i<256; i++){ 212 *(ulong*)(t+0) = a; /* CALL traplink(SB) */ 213 *(ulong*)(t+4) = 0xa7480000; /* MOVW PSR, R19 */ 214 a -= 16/4; 215 t += 16; 216 } 217 218 #ifdef notdef 219 flushpage(TRAPS); 220 #else 221 flushicache(); 222 #endif 223 224 puttbr(TRAPS); 225 setpsr(getpsr()|PSRET|SPL(15)); /* enable traps, not interrupts */ 226 } 227 228 void 229 mulu(ulong u1, ulong u2, ulong *lop, ulong *hip) 230 { 231 ulong lo1, lo2, hi1, hi2, lo, hi, t1, t2, t; 232 233 lo1 = u1 & 0xffff; 234 lo2 = u2 & 0xffff; 235 hi1 = u1 >> 16; 236 hi2 = u2 >> 16; 237 238 lo = lo1 * lo2; 239 t1 = lo1 * hi2; 240 t2 = lo2 * hi1; 241 hi = hi1 * hi2; 242 t = lo; 243 lo += t1 << 16; 244 if(lo < t) 245 hi++; 246 t = lo; 247 lo += t2 << 16; 248 if(lo < t) 249 hi++; 250 hi += (t1 >> 16) + (t2 >> 16); 251 *lop = lo; 252 *hip = hi; 253 } 254 255 void 256 muls(long l1, long l2, long *lop, long *hip) 257 { 258 ulong t, lo, hi; 259 ulong mlo, mhi; 260 int sign; 261 262 sign = 0; 263 if(l1 < 0){ 264 sign ^= 1; 265 l1 = -l1; 266 } 267 if(l2 < 0){ 268 sign ^= 1; 269 l2 = -l2; 270 } 271 mulu(l1, l2, &mlo, &mhi); 272 lo = mlo; 273 hi = mhi; 274 if(sign){ 275 t = lo = ~lo; 276 hi = ~hi; 277 lo++; 278 if(lo < t) 279 hi++; 280 } 281 *lop = lo; 282 *hip = hi; 283 } 284 285 int 286 domuldiv(ulong iw, Ureg *ur) 287 { 288 long op1, op2; 289 long *regp; 290 long *regs; 291 292 regs = (long*)ur; 293 if(iw & (1<<13)){ /* signed immediate */ 294 op2 = iw & 0x1FFF; 295 if(op2 & 0x1000) 296 op2 |= ~0x1FFF; 297 }else 298 op2 = regs[iw&0x1F]; 299 op1 = regs[(iw>>14)&0x1F]; 300 regp = ®s[(iw>>25)&0x1F]; 301 302 if(iw & (4<<19)){ /* divide */ 303 if(ur->y!=0 && ur->y!=~0){ 304 unimp: 305 ur->tbr = 37; /* "unimplemented instruction" */ 306 return 0; /* complex Y is too hard */ 307 } 308 if(op2 == 0){ 309 ur->tbr = 42; /* "zero divide" */ 310 return 0; 311 } 312 if(iw & (1<<19)){ 313 if(ur->y && (op1&(1<<31))==0) 314 goto unimp; /* Y not sign extension */ 315 *regp = op1 / op2; 316 }else{ 317 if(ur->y) 318 goto unimp; 319 *regp = (ulong)op1 / (ulong)op2; 320 } 321 }else{ 322 if(iw & (1<<19)) 323 muls(op1, op2, regp, (long*)&ur->y); 324 else 325 mulu(op1, op2, (ulong*)regp, &ur->y); 326 } 327 if(iw & (16<<19)){ /* set CC */ 328 ur->psr &= ~(0xF << 20); 329 if(*regp & (1<<31)) 330 ur->psr |= 8 << 20; /* N */ 331 if(*regp == 0) 332 ur->psr |= 4 << 20; /* Z */ 333 /* BUG: don't get overflow right on divide */ 334 } 335 ur->pc += 4; 336 ur->npc = ur->pc+4; 337 return 1; 338 } 339 340 void 341 dumpregs(Ureg *ur) 342 { 343 int i; 344 ulong *l; 345 346 if(up) { 347 print("registers for %s %ld\n",up->text,up->pid); 348 if(ur->usp < (ulong)up->kstack || 349 ur->usp > (ulong)up->kstack+KSTACK-8) 350 print("invalid stack pointer\n"); 351 } else 352 print("registers for kernel\n"); 353 354 print("PSR=%lux PC=%lux TBR=%lux\n", ur->psr, ur->pc, ur->tbr); 355 l = &ur->r0; 356 for(i=0; i<32; i+=2, l+=2) 357 print("R%d\t%.8lux\tR%d\t%.8lux\n", i, l[0], i+1, l[1]); 358 } 359 360 361 /* This routine must save the values of registers the user is not permitted to 362 * write from devproc and the restore the saved values before returning 363 */ 364 void 365 setregisters(Ureg *xp, char *pureg, char *uva, int n) 366 { 367 ulong psr; 368 369 psr = xp->psr; 370 memmove(pureg, uva, n); 371 xp->psr = psr; 372 } 373 374 void 375 dumpstack(void) 376 { 377 } 378 379 /* 380 * Must only be called splhi() when it is safe to spllo(). Because the FP unit 381 * traps if you touch it when an exception is pending, and because if you 382 * trap with ET==0 you halt, this routine sets some global flags to enable 383 * the rest of the system to handle the trap that might occur here without 384 * upsetting the kernel. Shouldn't be necessary, but safety first. 385 */ 386 int 387 fpquiet(void) 388 { 389 int i, notrap; 390 ulong fsr; 391 char buf[128]; 392 393 i = 0; 394 notrap = 1; 395 up->fpstate = FPINACTIVE; 396 for(;;){ 397 m->fptrap = 0; 398 fsr = getfsr(); 399 if(m->fptrap){ 400 /* trap occurred and up->fpsave contains state */ 401 sprint(buf, "sys: %s", excname(8)); 402 #ifdef notdef 403 postnote(u->p, 1, buf, NDebug); 404 #else 405 panic(buf); 406 #endif 407 notrap = 0; 408 break; 409 } 410 if((fsr&(1<<13)) == 0) 411 break; 412 if(++i > 1000){ 413 print("fp not quiescent\n"); 414 break; 415 } 416 } 417 up->fpstate = FPACTIVE; 418 return notrap; 419 } 420 421 enum 422 { 423 SE_WRITE = 4<<5, 424 SE_PROT = 2<<2, 425 }; 426 427 static void 428 faultsparc(Ureg *ur) 429 { 430 ulong addr; 431 char buf[ERRMAX]; 432 int read; 433 ulong tbr, ser; 434 435 tbr = (ur->tbr&0xFFF)>>4; 436 addr = ur->pc; /* assume instr. exception */ 437 read = 1; 438 if(tbr == 9){ /* data access exception */ 439 addr = getrmmu(SFAR); 440 ser = getrmmu(SFSR); 441 if(ser&(SE_WRITE)) /* is SE_PROT needed? */ 442 read = 0; 443 } 444 445 up->dbgreg = ur; /* for remote acid */ 446 spllo(); 447 sprint(buf, "sys: trap: fault %s addr=0x%lux", 448 read? "read" : "write", addr); 449 450 if(up->type == Interp) 451 disfault(ur,buf); 452 dumpregs(ur); 453 panic("fault: %s", buf); 454 } 455 456 static void 457 faultasync(Ureg *ur) 458 { 459 int user; 460 461 print("interrupt 15 AFSR %lux AFAR %lux MFSR %lux MFAR %lux\n", 462 getphys(AFSR), getphys(AFAR), getphys(MFSR), getphys(MFAR)); 463 dumpregs(ur); 464 /* 465 * Clear interrupt 466 */ 467 putphys(PROCINTCLR, 1<<15); 468 user = !(ur->psr&PSRPSUPER); 469 if(user) 470 pexit("Suicide", 0); 471 panic("interrupt 15"); 472 } 473