trap.c 13 KB

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