trap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. * sheevaplug traps, exceptions, interrupts, system calls.
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "io.h"
  10. #include "ureg.h"
  11. #include "../port/error.h"
  12. #include "arm.h"
  13. enum {
  14. Ntimevec = 20 /* # of time buckets for each intr */
  15. };
  16. extern int notify(Ureg*);
  17. extern int ldrexvalid;
  18. typedef struct Vctl Vctl;
  19. typedef struct Vctl {
  20. Vctl* next; /* handlers on this vector */
  21. char *name; /* of driver, xallocated */
  22. void (*f)(Ureg*, void*); /* handler to call */
  23. void* a; /* argument to call it with */
  24. } Vctl;
  25. static Lock vctllock;
  26. static Vctl* vctl[32];
  27. uvlong ninterrupt;
  28. uvlong ninterruptticks;
  29. ulong intrtimes[256][Ntimevec];
  30. typedef struct Handler Handler;
  31. struct Handler {
  32. void (*r)(Ureg*, void*);
  33. void *a;
  34. char name[KNAMELEN];
  35. };
  36. static Handler irqlo[32];
  37. static Handler irqhi[32];
  38. static Handler irqbridge[32];
  39. static Lock irqlock;
  40. static int probing, trapped;
  41. typedef struct Irq Irq;
  42. struct Irq {
  43. ulong *irq;
  44. ulong *irqmask;
  45. Handler *irqvec;
  46. int nirqvec;
  47. char *name;
  48. };
  49. static Irq irqs[] = {
  50. [Irqlo] {&INTRREG->lo.irq, &INTRREG->lo.irqmask, irqlo, nelem(irqlo), "lo"},
  51. [Irqhi] {&INTRREG->hi.irq, &INTRREG->hi.irqmask, irqhi, nelem(irqhi), "hi"},
  52. [Irqbridge] {&CPUCSREG->irq, &CPUCSREG->irqmask, irqbridge, nelem(irqbridge), "bridge"},
  53. };
  54. /*
  55. * keep histogram of interrupt service times
  56. */
  57. void
  58. intrtime(Mach*, int vno)
  59. {
  60. ulong diff, x;
  61. if (m == nil)
  62. return;
  63. x = perfticks();
  64. diff = x - m->perf.intrts;
  65. m->perf.intrts = x;
  66. m->perf.inintr += diff;
  67. if(up == nil && m->perf.inidle > diff)
  68. m->perf.inidle -= diff;
  69. if (m->cpuhz == 0) /* not set yet? */
  70. return;
  71. diff /= (m->cpuhz/1000000)*100; /* quantum = 100µsec */
  72. if(diff >= Ntimevec)
  73. diff = Ntimevec-1;
  74. intrtimes[vno][diff]++;
  75. }
  76. void
  77. intrfmtcounts(char *s, char *se)
  78. {
  79. USED(s, se);
  80. }
  81. static void
  82. dumpcounts(void)
  83. {
  84. }
  85. void
  86. intrclear(int sort, int v)
  87. {
  88. *irqs[sort].irq = ~(1 << v);
  89. }
  90. void
  91. intrmask(int sort, int v)
  92. {
  93. *irqs[sort].irqmask &= ~(1 << v);
  94. }
  95. void
  96. intrunmask(int sort, int v)
  97. {
  98. *irqs[sort].irqmask |= 1 << v;
  99. }
  100. static void
  101. maskallints(void)
  102. {
  103. /* no fiq or ep in use */
  104. INTRREG->lo.irqmask = 0;
  105. INTRREG->hi.irqmask = 0;
  106. CPUCSREG->irqmask = 0;
  107. }
  108. void
  109. intrset(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
  110. {
  111. if(h->r != nil) {
  112. // iprint("duplicate irq: %s (%#p)\n", h->name, h->r);
  113. return;
  114. }
  115. h->r = f;
  116. h->a = a;
  117. strncpy(h->name, name, KNAMELEN-1);
  118. h->name[KNAMELEN-1] = 0;
  119. }
  120. void
  121. intrunset(Handler *h)
  122. {
  123. h->r = nil;
  124. h->a = nil;
  125. h->name[0] = 0;
  126. }
  127. void
  128. intrdel(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
  129. {
  130. if(h->r != f || h->a != a || strcmp(h->name, name) != 0)
  131. return;
  132. intrunset(h);
  133. }
  134. void
  135. intrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name)
  136. {
  137. //iprint("enabling intr %d vec %d for %s\n", sort, v, name);
  138. ilock(&irqlock);
  139. intrset(&irqs[sort].irqvec[v], f, a, name);
  140. intrunmask(sort, v);
  141. iunlock(&irqlock);
  142. }
  143. void
  144. intrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name)
  145. {
  146. ilock(&irqlock);
  147. intrdel(&irqs[sort].irqvec[v], f, a, name);
  148. intrmask(sort, v);
  149. iunlock(&irqlock);
  150. }
  151. /*
  152. * called by trap to handle interrupts
  153. */
  154. static void
  155. intrs(Ureg *ur, int sort)
  156. {
  157. int i, s;
  158. ulong ibits;
  159. Handler *h;
  160. Irq irq;
  161. irq = irqs[sort];
  162. ibits = *irq.irq;
  163. ibits &= *irq.irqmask;
  164. for(i = 0; i < irq.nirqvec && ibits; i++)
  165. if(ibits & (1<<i)){
  166. h = &irq.irqvec[i];
  167. if(h->r != nil){
  168. h->r(ur, h->a);
  169. splhi();
  170. intrtime(m, sort*32 + i);
  171. if (sort == Irqbridge && i == IRQcputimer0)
  172. m->inclockintr = 1;
  173. ibits &= ~(1<<i);
  174. }
  175. }
  176. if(ibits != 0) {
  177. iprint("spurious irq%s interrupt: %8.8lux\n", irq.name, ibits);
  178. s = splfhi();
  179. *irq.irq &= ibits;
  180. splx(s);
  181. }
  182. }
  183. void
  184. intrhi(Ureg *ureg, void*)
  185. {
  186. intrs(ureg, Irqhi);
  187. }
  188. void
  189. intrbridge(Ureg *ureg, void*)
  190. {
  191. intrs(ureg, Irqbridge);
  192. intrclear(Irqlo, IRQ0bridge);
  193. }
  194. void
  195. trapinit(void)
  196. {
  197. int i;
  198. CpucsReg *cpu;
  199. IntrReg *intr;
  200. Vectorpage *page0 = (Vectorpage*)HVECTORS;
  201. setr13(PsrMfiq, m->fiqstack + nelem(m->fiqstack));
  202. setr13(PsrMirq, m->irqstack + nelem(m->irqstack));
  203. setr13(PsrMabt, m->abtstack + nelem(m->abtstack));
  204. setr13(PsrMund, m->undstack + nelem(m->undstack));
  205. memmove(page0->vectors, vectors, sizeof page0->vectors);
  206. memmove(page0->vtable, vtable, sizeof page0->vtable);
  207. cacheuwbinv();
  208. cpu = CPUCSREG;
  209. cpu->cpucfg &= ~Cfgvecinithi;
  210. for(i = 0; i < nelem(irqlo); i++)
  211. intrunset(&irqlo[i]);
  212. for(i = 0; i < nelem(irqhi); i++)
  213. intrunset(&irqhi[i]);
  214. for(i = 0; i < nelem(irqbridge); i++)
  215. intrunset(&irqbridge[i]);
  216. /* disable all interrupts */
  217. intr = INTRREG;
  218. intr->lo.fiqmask = intr->hi.fiqmask = 0;
  219. intr->lo.irqmask = intr->hi.irqmask = 0;
  220. intr->lo.epmask = intr->hi.epmask = 0;
  221. cpu->irqmask = 0;
  222. /* clear interrupts */
  223. intr->lo.irq = intr->hi.irq = ~0;
  224. cpu->irq = ~0;
  225. intrenable(Irqlo, IRQ0hisum, intrhi, nil, "hi");
  226. intrenable(Irqlo, IRQ0bridge, intrbridge, nil, "bridge");
  227. }
  228. static char *trapnames[PsrMask+1] = {
  229. [ PsrMusr ] "user mode",
  230. [ PsrMfiq ] "fiq interrupt",
  231. [ PsrMirq ] "irq interrupt",
  232. [ PsrMsvc ] "svc/swi exception",
  233. [ PsrMabt ] "prefetch abort/data abort",
  234. [ PsrMabt+1 ] "data abort",
  235. [ PsrMund ] "undefined instruction",
  236. [ PsrMsys ] "sys trap",
  237. };
  238. static char *
  239. trapname(int psr)
  240. {
  241. char *s;
  242. s = trapnames[psr & PsrMask];
  243. if(s == nil)
  244. s = "unknown trap number in psr";
  245. return s;
  246. }
  247. /*
  248. * called by trap to handle access faults
  249. */
  250. static void
  251. faultarm(Ureg *ureg, uintptr va, int user, int read)
  252. {
  253. int n, insyscall;
  254. char buf[ERRMAX];
  255. if(up == nil) {
  256. dumpregs(ureg);
  257. panic("fault: nil up in faultarm, accessing %#p", va);
  258. }
  259. insyscall = up->insyscall;
  260. up->insyscall = 1;
  261. n = fault(va, read);
  262. if(n < 0){
  263. if(!user){
  264. dumpregs(ureg);
  265. panic("fault: kernel accessing %#p", va);
  266. }
  267. /* don't dump registers; programs suicide all the time */
  268. snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
  269. read? "read": "write", va);
  270. postnote(up, 1, buf, NDebug);
  271. }
  272. up->insyscall = insyscall;
  273. }
  274. /*
  275. * returns 1 if the instruction writes memory, 0 otherwise
  276. */
  277. int
  278. writetomem(ulong inst)
  279. {
  280. /* swap always write memory */
  281. if((inst & 0x0FC00000) == 0x01000000)
  282. return 1;
  283. /* loads and stores are distinguished by bit 20 */
  284. if(inst & (1<<20))
  285. return 0;
  286. return 1;
  287. }
  288. void
  289. trap(Ureg *ureg)
  290. {
  291. int user, x, rv, rem;
  292. ulong inst;
  293. u32int fsr;
  294. uintptr va;
  295. char buf[ERRMAX];
  296. if(up != nil)
  297. rem = (char*)ureg - up->kstack;
  298. else
  299. rem = (char*)ureg - ((char*)m + sizeof(Mach));
  300. if(rem < 256) {
  301. dumpstack();
  302. panic("trap %d bytes remaining, up %#p ureg %#p at pc %#ux",
  303. rem, up, ureg, ureg->pc);
  304. }
  305. user = (ureg->psr & PsrMask) == PsrMusr;
  306. if(ureg->type == PsrMabt+1)
  307. ureg->pc -= 8;
  308. else
  309. ureg->pc -= 4;
  310. m->inclockintr = 0;
  311. switch(ureg->type) {
  312. default:
  313. panic("unknown trap %d", ureg->type);
  314. break;
  315. case PsrMirq:
  316. ldrexvalid = 0;
  317. // splflo(); /* allow fast interrupts */
  318. intrs(ureg, Irqlo);
  319. m->intr++;
  320. break;
  321. case PsrMabt: /* prefetch fault */
  322. ldrexvalid = 0;
  323. faultarm(ureg, ureg->pc, user, 1);
  324. break;
  325. case PsrMabt+1: /* data fault */
  326. ldrexvalid = 0;
  327. va = farget();
  328. inst = *(ulong*)(ureg->pc);
  329. fsr = fsrget() & 0xf;
  330. if (probing && !user) {
  331. if (trapped++ > 0)
  332. panic("trap: recursive probe %#lux", va);
  333. ureg->pc += 4; /* continue at next instruction */
  334. break;
  335. }
  336. switch(fsr){
  337. case 0x0:
  338. panic("vector exception at %#ux", ureg->pc);
  339. break;
  340. case 0x1:
  341. case 0x3:
  342. if(user){
  343. snprint(buf, sizeof buf,
  344. "sys: alignment: pc %#ux va %#p\n",
  345. ureg->pc, va);
  346. postnote(up, 1, buf, NDebug);
  347. } else
  348. panic("kernel alignment: pc %#ux va %#p", ureg->pc, va);
  349. break;
  350. case 0x2:
  351. panic("terminal exception at %#ux", ureg->pc);
  352. break;
  353. case 0x4:
  354. case 0x6:
  355. case 0x8:
  356. case 0xa:
  357. case 0xc:
  358. case 0xe:
  359. panic("external abort %#ux pc %#ux addr %#px",
  360. fsr, ureg->pc, va);
  361. break;
  362. case 0x5: /* translation fault, no section entry */
  363. case 0x7: /* translation fault, no page entry */
  364. faultarm(ureg, va, user, !writetomem(inst));
  365. break;
  366. case 0x9:
  367. case 0xb:
  368. /* domain fault, accessing something we shouldn't */
  369. if(user){
  370. snprint(buf, sizeof buf,
  371. "sys: access violation: pc %#ux va %#p\n",
  372. ureg->pc, va);
  373. postnote(up, 1, buf, NDebug);
  374. } else
  375. panic("kernel access violation: pc %#ux va %#p",
  376. ureg->pc, va);
  377. break;
  378. case 0xd:
  379. case 0xf:
  380. /* permission error, copy on write or real permission error */
  381. faultarm(ureg, va, user, !writetomem(inst));
  382. break;
  383. }
  384. break;
  385. case PsrMund: /* undefined instruction */
  386. if(user){
  387. /* look for floating point instructions to interpret */
  388. x = spllo();
  389. rv = fpiarm(ureg);
  390. splx(x);
  391. if(rv == 0){
  392. ldrexvalid = 0;
  393. snprint(buf, sizeof buf,
  394. "undefined instruction: pc %#ux\n",
  395. ureg->pc);
  396. postnote(up, 1, buf, NDebug);
  397. }
  398. }else{
  399. iprint("undefined instruction: pc %#ux inst %#ux\n",
  400. ureg->pc, ((u32int*)ureg->pc)[-2]);
  401. panic("undefined instruction");
  402. }
  403. break;
  404. }
  405. splhi();
  406. /* delaysched set because we held a lock or because our quantum ended */
  407. if(up && up->delaysched && m->inclockintr){
  408. ldrexvalid = 0;
  409. sched();
  410. splhi();
  411. }
  412. if(user){
  413. if(up->procctl || up->nnote)
  414. notify(ureg);
  415. kexit(ureg);
  416. }
  417. }
  418. int
  419. isvalidaddr(void *v)
  420. {
  421. return (uintptr)v >= KZERO;
  422. }
  423. void
  424. dumplongs(char *msg, ulong *v, int n)
  425. {
  426. int i, l;
  427. l = 0;
  428. iprint("%s at %.8p: ", msg, v);
  429. for(i=0; i<n; i++){
  430. if(l >= 4){
  431. iprint("\n %.8p: ", v);
  432. l = 0;
  433. }
  434. if(isvalidaddr(v)){
  435. iprint(" %.8lux", *v++);
  436. l++;
  437. }else{
  438. iprint(" invalid");
  439. break;
  440. }
  441. }
  442. iprint("\n");
  443. }
  444. static void
  445. dumpstackwithureg(Ureg *ureg)
  446. {
  447. iprint("ktrace /kernel/path %#.8ux %#.8ux %#.8ux # pc, sp, link\n",
  448. ureg->pc, ureg->sp, ureg->r14);
  449. delay(2000);
  450. #ifdef AMBITIOUS
  451. uintptr l, i, v, estack;
  452. u32int *p;
  453. i = 0;
  454. if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
  455. estack = (uintptr)up->kstack+KSTACK;
  456. else if((uintptr)&l >= (uintptr)m->stack
  457. && (uintptr)&l <= (uintptr)m+MACHSIZE)
  458. estack = (uintptr)m+MACHSIZE;
  459. else{
  460. if(up != nil)
  461. iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
  462. else
  463. iprint("&m %#p &l %#p\n", m, &l);
  464. return;
  465. }
  466. for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
  467. v = *(uintptr*)l;
  468. if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
  469. v -= sizeof(u32int);
  470. p = (u32int*)v;
  471. if((*p & 0x0f000000) == 0x0b000000){ /* magic */
  472. iprint("%#8.8lux=%#8.8lux ", l, v);
  473. i++;
  474. }
  475. }
  476. if(i == 4){
  477. i = 0;
  478. iprint("\n");
  479. }
  480. }
  481. if(i)
  482. iprint("\n");
  483. #endif
  484. }
  485. /*
  486. * Fill in enough of Ureg to get a stack trace, and call a function.
  487. * Used by debugging interface rdb.
  488. */
  489. void
  490. callwithureg(void (*fn)(Ureg*))
  491. {
  492. Ureg ureg;
  493. ureg.pc = getcallerpc(&fn);
  494. ureg.sp = PTR2UINT(&fn);
  495. fn(&ureg);
  496. }
  497. void
  498. dumpstack(void)
  499. {
  500. callwithureg(dumpstackwithureg);
  501. }
  502. void
  503. dumpregs(Ureg* ureg)
  504. {
  505. int s;
  506. if (ureg == nil) {
  507. iprint("trap: no user process\n");
  508. return;
  509. }
  510. s = splhi();
  511. iprint("trap: %s", trapname(ureg->type));
  512. if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
  513. iprint(" in %s", trapname(ureg->psr));
  514. iprint("\n");
  515. iprint("psr %8.8ux type %2.2ux pc %8.8ux link %8.8ux\n",
  516. ureg->psr, ureg->type, ureg->pc, ureg->link);
  517. iprint("R14 %8.8ux R13 %8.8ux R12 %8.8ux R11 %8.8ux R10 %8.8ux\n",
  518. ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
  519. iprint("R9 %8.8ux R8 %8.8ux R7 %8.8ux R6 %8.8ux R5 %8.8ux\n",
  520. ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
  521. iprint("R4 %8.8ux R3 %8.8ux R2 %8.8ux R1 %8.8ux R0 %8.8ux\n",
  522. ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
  523. iprint("stack is at %#p\n", ureg);
  524. iprint("pc %#ux link %#ux\n", ureg->pc, ureg->link);
  525. if(up)
  526. iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
  527. else
  528. iprint("kernel stack: %8.8lux-%8.8lux\n",
  529. (ulong)(m+1), (ulong)m+BY2PG-4);
  530. dumplongs("stack", (ulong *)(ureg + 1), 16);
  531. delay(2000);
  532. dumpstack();
  533. splx(s);
  534. }
  535. void
  536. idlehands(void)
  537. {
  538. extern void _idlehands(void);
  539. _idlehands();
  540. }
  541. vlong
  542. probeaddr(uintptr addr)
  543. {
  544. vlong v;
  545. static Lock fltlck;
  546. ilock(&fltlck);
  547. trapped = 0;
  548. probing = 1;
  549. coherence();
  550. v = *(ulong *)addr; /* this may cause a fault */
  551. USED(probing);
  552. coherence();
  553. probing = 0;
  554. coherence();
  555. if (trapped)
  556. v = -1;
  557. iunlock(&fltlck);
  558. return v;
  559. }