trap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include <tos.h>
  16. #include "ureg.h"
  17. #include "../port/pmc.h"
  18. #include "io.h"
  19. #include "encoding.h"
  20. enum traps {
  21. InstructionAlignment = 0,
  22. InstructionAccessFault,
  23. IllegalInstruction,
  24. Breakpoint,
  25. Trap4Reserved,
  26. LoadAccessFault,
  27. AMOAddressMisaligned,
  28. Store_AMOAccessFault,
  29. EnvironmentCall,
  30. LastTrap = EnvironmentCall,
  31. InterruptMask = 0x8000000000000000ULL
  32. };
  33. enum interrupts {
  34. UserSoftware,
  35. SupervisorSoftware,
  36. Interrupt2Reserved,
  37. Interrupt3eserved,
  38. UserTimer,
  39. SupervisorTimer,
  40. LastInterrupt = SupervisorTimer
  41. };
  42. void msg(char *);
  43. int getchar(void);
  44. // counters. Set by assembly code.
  45. // interrupt enter and exit, systecm call enter and exit.
  46. unsigned long ire, irx, sce, scx;
  47. // Did we start doing an exit for the interrupts?
  48. // ir exit entry :-)
  49. unsigned long irxe;
  50. extern int notify(Ureg*);
  51. //static void debugbpt(Ureg*, void*);
  52. static void faultarch(Ureg*);
  53. //static void doublefault(Ureg*, void*);
  54. //static void unexpected(Ureg*, void*);
  55. //static void expected(Ureg*, void*);
  56. static void dumpstackwithureg(Ureg*);
  57. //extern int bus_irq_setup(Vctl*);
  58. static Lock vctllock;
  59. static Vctl *vctl[256];
  60. typedef struct Intrtime Intrtime;
  61. struct Intrtime {
  62. uint64_t count;
  63. uint64_t cycles;
  64. };
  65. static Intrtime intrtimes[256];
  66. void*
  67. intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
  68. {
  69. int vno;
  70. Vctl *v;
  71. if(f == nil){
  72. print("intrenable: nil handler for %d, tbdf %#x for %s\n",
  73. irq, tbdf, name);
  74. panic("FIX ME");
  75. return nil;
  76. }
  77. v = malloc(sizeof(Vctl));
  78. v->isintr = 1;
  79. v->Vkey.irq = irq;
  80. v->Vkey.tbdf = tbdf;
  81. v->f = f;
  82. v->a = a;
  83. strncpy(v->name, name, KNAMELEN-1);
  84. v->name[KNAMELEN-1] = 0;
  85. ilock(&vctllock);
  86. print(" ignoring bus_irq_setup");
  87. //vno = bus_irq_setup(v);
  88. vno = irq;
  89. if(vno == -1){
  90. iunlock(&vctllock);
  91. print("intrenable: couldn't enable irq %d, tbdf %#x for %s\n",
  92. irq, tbdf, v->name);
  93. panic("DIE");
  94. free(v);
  95. return nil;
  96. }
  97. if(vctl[vno]){
  98. if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)
  99. print("intrenable: handler: %s %s %#p %#p %#p %#p",
  100. vctl[v->vno]->name, v->name,
  101. vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);
  102. panic("CONFLICT");
  103. }
  104. v->vno = vno;
  105. v->next = vctl[vno];
  106. vctl[vno] = v;
  107. iunlock(&vctllock);
  108. if(v->mask)
  109. v->mask(&v->Vkey, 0);
  110. /*
  111. * Return the assigned vector so intrdisable can find
  112. * the handler; the IRQ is useless in the wonderful world
  113. * of the IOAPIC.
  114. */
  115. return v;
  116. }
  117. static const char *const excname[] = {
  118. "Instruction address misaligned",
  119. "Instruction access fault",
  120. "Illegal instruction",
  121. "Breakpoint",
  122. "Load address misaligned",
  123. "Load access fault",
  124. "Store address misaligned",
  125. "Store access fault",
  126. "Environment call from U-mode",
  127. "Environment call from S-mode",
  128. "Environment call from H-mode",
  129. "Environment call from M-mode"
  130. };
  131. static void print_trap_information(const Ureg *ureg)
  132. {
  133. Proc *up = externup();
  134. const char *previous_mode;
  135. int status = ureg->status;
  136. /* Leave some space around the trap message */
  137. print("\n PID %d\n", up ? up->pid : -1);
  138. if (ureg->cause < nelem(excname))
  139. print("Exception: %s\n",
  140. excname[ureg->cause]);
  141. else
  142. print("Trap: Unknown cause %p\n",
  143. (void *)ureg->cause);
  144. previous_mode = status & 0x100 ? "Supervisor" : "User";
  145. print("Previous mode: %s\n", previous_mode);
  146. print("Bad instruction pc: %p\n", (void *)ureg->epc);
  147. print("Bad address: %p\n", (void *)ureg->badaddr);
  148. print("Stored ip: %p\n", (void*) ureg->ip);
  149. print("Stored sp: %p\n", (void*) ureg->sp);
  150. }
  151. void trap_handler(Ureg *ureg) {
  152. switch(ureg->cause) {
  153. case CAUSE_MISALIGNED_FETCH:
  154. print_trap_information(ureg);
  155. panic("misaligned fetch, firmware is supposed to do this");
  156. return;
  157. break;
  158. case CAUSE_ILLEGAL_INSTRUCTION:
  159. print_trap_information(ureg);
  160. panic("illegal instruction, going to die");
  161. return;
  162. break;
  163. case CAUSE_BREAKPOINT:
  164. print_trap_information(ureg);
  165. panic("can't handle breakpoints yet\n");
  166. return;
  167. break;
  168. case CAUSE_FAULT_FETCH:
  169. case CAUSE_FAULT_LOAD:
  170. case CAUSE_FAULT_STORE:
  171. if (0) print_trap_information(ureg);
  172. faultarch(ureg);
  173. return;
  174. break;
  175. case CAUSE_USER_ECALL:
  176. case CAUSE_HYPERVISOR_ECALL:
  177. case CAUSE_MACHINE_ECALL:
  178. print_trap_information(ureg);
  179. panic("Can't do ecalls here");
  180. return;
  181. break;
  182. case CAUSE_MISALIGNED_LOAD:
  183. print("hgroup 2\n");
  184. print_trap_information(ureg);
  185. panic("misaligned LOAD, we don't do these");
  186. return;
  187. break;
  188. case CAUSE_MISALIGNED_STORE:
  189. print_trap_information(ureg);
  190. panic("misaligned STORE, we don't do these");
  191. return;
  192. break;
  193. default:
  194. print_trap_information(ureg);
  195. panic("WTF\n");
  196. return;
  197. break;
  198. }
  199. }
  200. int
  201. intrdisable(void* vector)
  202. {
  203. Vctl *v, *x, **ll;
  204. //extern int ioapicintrdisable(int);
  205. ilock(&vctllock);
  206. v = vector;
  207. if(v == nil || vctl[v->vno] != v)
  208. panic("intrdisable: v %#p", v);
  209. for(ll = vctl+v->vno; x = *ll; ll = &x->next)
  210. if(v == x)
  211. break;
  212. if(x != v)
  213. panic("intrdisable: v %#p", v);
  214. if(v->mask)
  215. v->mask(&v->Vkey, 1);
  216. v->f(nil, v->a);
  217. *ll = v->next;
  218. panic("ioapicintrdisable");
  219. //ioapicintrdisable(v->vno);
  220. iunlock(&vctllock);
  221. free(v);
  222. return 0;
  223. }
  224. static int32_t
  225. irqallocread(Chan* c, void *vbuf, int32_t n, int64_t offset)
  226. {
  227. char *buf, *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1];
  228. int m, vno;
  229. int32_t oldn;
  230. Intrtime *t;
  231. Vctl *v;
  232. if(n < 0 || offset < 0)
  233. error(Ebadarg);
  234. oldn = n;
  235. buf = vbuf;
  236. for(vno=0; vno<nelem(vctl); vno++){
  237. for(v=vctl[vno]; v; v=v->next){
  238. t = intrtimes + vno;
  239. m = snprint(str, sizeof str, "%11d %11d %20llu %20llu %-*.*s %.*s\n",
  240. vno, v->Vkey.irq, t->count, t->cycles, 8, 8, v->type, KNAMELEN, v->name);
  241. if(m <= offset) /* if do not want this, skip entry */
  242. offset -= m;
  243. else{
  244. /* skip offset bytes */
  245. m -= offset;
  246. p = str+offset;
  247. offset = 0;
  248. /* write at most max(n,m) bytes */
  249. if(m > n)
  250. m = n;
  251. memmove(buf, p, m);
  252. n -= m;
  253. buf += m;
  254. if(n == 0)
  255. return oldn;
  256. }
  257. }
  258. }
  259. return oldn - n;
  260. }
  261. void
  262. trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
  263. {
  264. Vctl *v;
  265. if(vno < 0 || vno >= 256)
  266. panic("trapenable: vno %d\n", vno);
  267. v = malloc(sizeof(Vctl));
  268. v->type = "trap";
  269. v->Vkey.tbdf = -1;
  270. v->f = f;
  271. v->a = a;
  272. strncpy(v->name, name, KNAMELEN);
  273. v->name[KNAMELEN-1] = 0;
  274. ilock(&vctllock);
  275. v->next = vctl[vno];
  276. vctl[vno] = v;
  277. iunlock(&vctllock);
  278. }
  279. #if 0
  280. static void
  281. nmienable(void)
  282. {
  283. panic("nmienable");
  284. }
  285. #endif
  286. static void riscvtimer(struct Ureg *u, void *_)
  287. {
  288. timerintr(u, 0);
  289. }
  290. void
  291. trapinit(void)
  292. {
  293. // basically done in firmware.
  294. addarchfile("irqalloc", 0444, irqallocread, nil);
  295. intrenable(5, riscvtimer, nil, 0, "timer");
  296. }
  297. /*
  298. * keep interrupt service times and counts
  299. */
  300. void
  301. intrtime(int vno)
  302. {
  303. Proc *up = externup();
  304. uint64_t diff, x;
  305. x = perfticks();
  306. diff = x - machp()->perf.intrts;
  307. machp()->perf.intrts = x;
  308. machp()->perf.inintr += diff;
  309. if(up == nil && machp()->perf.inidle > diff)
  310. machp()->perf.inidle -= diff;
  311. intrtimes[vno].cycles += diff;
  312. intrtimes[vno].count++;
  313. }
  314. static void
  315. pmcnop(Mach *m)
  316. {
  317. }
  318. void (*_pmcupdate)(Mach *m) = pmcnop;
  319. /* go to user space */
  320. void
  321. kexit(Ureg* u)
  322. {
  323. Proc *up = externup();
  324. uint64_t t;
  325. Tos *tos;
  326. Mach *mp;
  327. /*
  328. * precise time accounting, kernel exit
  329. * initialized in exec, sysproc.c
  330. */
  331. tos = (Tos*)(USTKTOP-sizeof(Tos));
  332. if (0) print("USTKTOP %p sizeof(Tos) %d tos %p\n", (void *)USTKTOP, sizeof(Tos), tos);
  333. cycles(&t);
  334. if (1) {
  335. if (0) print("tos is %p, &tos->kcycles is %p, up is %p\n", tos, &tos->kcycles, up);
  336. tos->kcycles += t - up->kentry;
  337. tos->pcycles = up->pcycles;
  338. tos->pid = up->pid;
  339. if (up->ac != nil)
  340. mp = up->ac;
  341. else
  342. mp = machp();
  343. if (0) print("kexit: mp is %p\n", mp);
  344. tos->core = mp->machno;
  345. if (0) print("kexit: mp is %p\n", mp);
  346. tos->nixtype = mp->NIX.nixtype;
  347. if (0) print("kexit: mp is %p\n", mp);
  348. //_pmcupdate(m);
  349. /*
  350. * The process may change its core.
  351. * Be sure it has the right cyclefreq.
  352. */
  353. tos->cyclefreq = mp->cyclefreq;
  354. if (0) print("kexit: mp is %p\n", mp);
  355. }
  356. if (0) print("kexit: done\n");
  357. }
  358. void
  359. kstackok(void)
  360. {
  361. Proc *up = externup();
  362. if(up == nil){
  363. uintptr_t *stk = (uintptr_t*)machp()->stack;
  364. if(*stk != STACKGUARD)
  365. panic("trap: mach %d machstk went through bottom %p\n", machp()->machno, machp()->stack);
  366. } else {
  367. uintptr_t *stk = (uintptr_t*)up->kstack;
  368. if(*stk != STACKGUARD)
  369. panic("trap: proc %d kstack went through bottom %p\n", up->pid, up->kstack);
  370. }
  371. }
  372. void
  373. _trap(Ureg *ureg)
  374. {
  375. if (0) msg("+trap\n");
  376. if (0) print("_trap\n");
  377. /*
  378. * If it's a real trap in this core, then we want to
  379. * use the hardware cr2 register.
  380. * We cannot do this in trap() because application cores
  381. * would update m->cr2 with their cr2 values upon page faults,
  382. * and then call trap().
  383. * If we do this in trap(), we would overwrite that with our own cr2.
  384. */
  385. switch(ureg->cause){
  386. case CAUSE_FAULT_FETCH:
  387. if (0) print("FETCH FAULT %p\n", ureg->ip);
  388. ureg->ftype = FT_EXEC;
  389. machp()->MMU.badaddr = ureg->badaddr;
  390. break;
  391. case CAUSE_FAULT_LOAD:
  392. if (0) print("LOAD FAULT %p\n", ureg->ip);
  393. ureg->ftype = FT_READ;
  394. machp()->MMU.badaddr = ureg->badaddr;
  395. break;
  396. case CAUSE_FAULT_STORE:
  397. if (0) print("STORE FAULT %p\n", ureg->ip);
  398. ureg->ftype = FT_WRITE;
  399. machp()->MMU.badaddr = ureg->badaddr;
  400. break;
  401. }
  402. trap(ureg);
  403. }
  404. void consread(void)
  405. {
  406. int c;
  407. if (0) print("consrad\n");
  408. c = getchar();
  409. if (c >= 0) {
  410. if (0) print("WROTE '%c'\n", c);
  411. void kbdputsc(int data, int _);
  412. kbdputsc(c, 0);
  413. }
  414. }
  415. static int lastvno;
  416. /*
  417. * All traps come here. It is slower to have all traps call trap()
  418. * rather than directly vectoring the handler. However, this avoids a
  419. * lot of code duplication and possible bugs. The only exception is
  420. * VectorSYSCALL.
  421. * Trap is called with interrupts disabled via interrupt-gates.
  422. */
  423. void
  424. trap(Ureg *ureg)
  425. {
  426. int clockintr, vno, user, interrupt;
  427. // cache the previous vno to see what might be causing
  428. // trouble
  429. vno = ureg->cause & ~InterruptMask;
  430. interrupt = !! (ureg->cause & InterruptMask);
  431. //print("T 0x%llx", ureg->cause);
  432. Mach *m =machp();
  433. //if (sce > scx) iprint("====================");
  434. lastvno = vno;
  435. if (m < (Mach *)(1ULL<<63))
  436. die("bogus mach");
  437. Proc *up = externup();
  438. char buf[ERRMAX];
  439. Vctl *ctl, *v;
  440. machp()->perf.intrts = perfticks();
  441. user = userureg(ureg);
  442. if(user && (machp()->NIX.nixtype == NIXTC)){
  443. if (0)print("call cycles\n");
  444. up->dbgreg = ureg;
  445. cycles(&up->kentry);
  446. if (0)print("done\n");
  447. }
  448. clockintr = interrupt && vno == SupervisorTimer;
  449. if (0 && clockintr) print("C");
  450. //print("clockintr %d\n", clockintr);
  451. //_pmcupdate(machp());
  452. if (!interrupt){
  453. if (0) print("trap_handler\n");
  454. trap_handler(ureg);
  455. } else {
  456. write_csr(sip, 0);
  457. //print("check vno %d\n", vno);
  458. if(ctl = vctl[vno]){
  459. if(ctl->isintr){
  460. machp()->intr++;
  461. machp()->lastintr = ctl->Vkey.irq;
  462. }else
  463. if(up)
  464. up->nqtrap++;
  465. if(ctl->isr){
  466. ctl->isr(vno);
  467. if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr);
  468. }
  469. for(v = ctl; v != nil; v = v->next){
  470. if(v->f){
  471. if (0) print("F");
  472. v->f(ureg, v->a);
  473. if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f);
  474. }
  475. }
  476. if(ctl->eoi){
  477. ctl->eoi(vno);
  478. if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi);
  479. }
  480. intrtime(vno);
  481. if(ctl->isintr){
  482. if (clockintr)
  483. oprof_alarm_handler(ureg);
  484. if(up && !clockintr)
  485. preempted();
  486. }
  487. } else if(vno < nelem(excname) && user){
  488. panic("OOR\n");
  489. spllo();
  490. snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
  491. postnote(up, 1, buf, NDebug);
  492. } else if ((interrupt && vno > LastInterrupt) || (vno > LastTrap)) {
  493. panic("UNK\n");
  494. /*
  495. * An unknown interrupt.
  496. */
  497. iprint("cpu%d: spurious interrupt %d, last %d\n",
  498. machp()->machno, vno, machp()->lastintr);
  499. intrtime(vno);
  500. if(user)
  501. kexit(ureg);
  502. return;
  503. } else {
  504. #if 0
  505. if(vno == VectorNMI){
  506. nmienable();
  507. if(machp()->machno != 0){
  508. iprint("cpu%d: PC %#llx\n",
  509. machp()->machno, ureg->ip);
  510. for(;;);
  511. }
  512. }
  513. #endif
  514. if (0) dumpregs(ureg);
  515. if(!user){
  516. ureg->sp = PTR2UINT(&ureg->sp);
  517. dumpstackwithureg(ureg);
  518. }
  519. if(vno < nelem(excname))
  520. panic("%s", excname[vno]);
  521. panic("unknown trap/intr: %d\n", vno);
  522. }
  523. }
  524. splhi();
  525. /* delaysched set because we held a lock or because our quantum ended */
  526. if(up && up->delaysched && clockintr){
  527. #if 0
  528. if(0)
  529. if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0){
  530. if(!waserror()){
  531. up->ac = getac(up, -1);
  532. poperror();
  533. runacore();
  534. return;
  535. }
  536. }
  537. #endif
  538. sched();
  539. splhi();
  540. }
  541. //print("DUN\n");
  542. if(user){
  543. if(up && up->procctl || up->nnote)
  544. notify(ureg);
  545. kexit(ureg);
  546. }
  547. //print("ALL DONE TRAP\n");
  548. }
  549. /*
  550. * Dump general registers.
  551. */
  552. void
  553. dumpgpr(Ureg* ureg)
  554. {
  555. Proc *up = externup();
  556. if(up != nil)
  557. print("cpu%d: ureg %p, registers for %s %d\n",
  558. machp()->machno, ureg, up->text, up->pid);
  559. else
  560. print("cpu%d: registers for kernel\n", machp()->machno);
  561. print("ip %#llx\n", ureg->ip);
  562. print("sp %#llx\n", ureg->sp);
  563. print("gp %#llx\n", ureg->gp);
  564. print("tp %#llx\n", ureg->tp);
  565. print("t0 %#llx\n", ureg->t0);
  566. print("t1 %#llx\n", ureg->t1);
  567. print("t2 %#llx\n", ureg->t2);
  568. print("s0 %#llx\n", ureg->s0);
  569. print("s1 %#llx\n", ureg->s1);
  570. print("a0 %#llx\n", ureg->a0);
  571. print("a1 %#llx\n", ureg->a1);
  572. print("a2 %#llx\n", ureg->a2);
  573. print("a3 %#llx\n", ureg->a3);
  574. print("a4 %#llx\n", ureg->a4);
  575. print("a5 %#llx\n", ureg->a5);
  576. print("a6 %#llx\n", ureg->a6);
  577. print("a7 %#llx\n", ureg->a7);
  578. print("s2 %#llx\n", ureg->s2);
  579. print("s3 %#llx\n", ureg->s3);
  580. print("s4 %#llx\n", ureg->s4);
  581. print("s5 %#llx\n", ureg->s5);
  582. print("s6 %#llx\n", ureg->s6);
  583. print("s7 %#llx\n", ureg->s7);
  584. print("s8 %#llx\n", ureg->s8);
  585. print("s9 %#llx\n", ureg->s9);
  586. print("s10 %#llx\n", ureg->s10);
  587. print("s11 %#llx\n", ureg->s11);
  588. print("t3 %#llx\n", ureg->t3);
  589. print("t4 %#llx\n", ureg->t4);
  590. print("t5 %#llx\n", ureg->t5);
  591. print("t6 %#llx\n", ureg->t6);
  592. print("status %#llx\n", ureg->status);
  593. print("epc %#llx\n", ureg->epc);
  594. print("badaddr %#llx\n", ureg->badaddr);
  595. print("cause %#llx\n", ureg->cause);
  596. print("insnn %#llx\n", ureg->insnn);
  597. print("bp %#llx\n", ureg->bp);
  598. print("ftype %#llx\n", ureg->ftype);
  599. print("m\t%#16.16p\nup\t%#16.16p\n", machp(), up);
  600. }
  601. void
  602. dumpregs(Ureg* ureg)
  603. {
  604. dumpgpr(ureg);
  605. }
  606. /*
  607. * Fill in enough of Ureg to get a stack trace, and call a function.
  608. * Used by debugging interface rdb.
  609. */
  610. void
  611. callwithureg(void (*fn)(Ureg*))
  612. {
  613. Ureg ureg;
  614. ureg.ip = getcallerpc();
  615. ureg.sp = PTR2UINT(&fn);
  616. fn(&ureg);
  617. }
  618. static void
  619. dumpstackwithureg(Ureg* ureg)
  620. {
  621. Proc *up = externup();
  622. uintptr_t l, v, i, estack;
  623. // extern char etext;
  624. int x;
  625. if (0) { //if((s = getconf("*nodumpstack")) != nil && atoi(s) != 0){
  626. iprint("dumpstack disabled\n");
  627. return;
  628. }
  629. iprint("dumpstack\n");
  630. x = 0;
  631. //x += iprint("ktrace 9%s %#p %#p\n", strrchr(conffile, '/')+1, ureg->ip, ureg->sp);
  632. i = 0;
  633. if(up != nil
  634. // && (uintptr)&l >= (uintptr)up->kstack
  635. && (uintptr_t)&l <= (uintptr_t)up->kstack+KSTACK)
  636. estack = (uintptr_t)up->kstack+KSTACK;
  637. else if((uintptr_t)&l >= machp()->stack && (uintptr_t)&l <= machp()->stack+MACHSTKSZ)
  638. estack = machp()->stack+MACHSTKSZ;
  639. else{
  640. if(up != nil)
  641. iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
  642. else
  643. iprint("&m %#p &l %#p\n", machp(), &l);
  644. return;
  645. }
  646. x += iprint("estackx %#p\n", estack);
  647. for(l = (uintptr_t)&l; l < estack; l += sizeof(uintptr_t)){
  648. v = *(uintptr_t*)l;
  649. if((KTZERO < v && v < (uintptr_t)&etext)
  650. || ((uintptr_t)&l < v && v < estack) || estack-l < 256){
  651. x += iprint("%#16.16p=%#16.16p ", l, v);
  652. i++;
  653. }
  654. if(i == 2){
  655. i = 0;
  656. x += iprint("\n");
  657. }
  658. }
  659. if(i)
  660. iprint("\n");
  661. }
  662. void
  663. dumpstack(void)
  664. {
  665. callwithureg(dumpstackwithureg);
  666. }
  667. #if 0
  668. static void
  669. debugbpt(Ureg* ureg, void* v)
  670. {
  671. Proc *up = externup();
  672. char buf[ERRMAX];
  673. if(up == 0)
  674. panic("kernel bpt");
  675. /* restore pc to instruction that caused the trap */
  676. ureg->ip--;
  677. sprint(buf, "sys: breakpoint");
  678. postnote(up, 1, buf, NDebug);
  679. }
  680. static void
  681. doublefault(Ureg* ureg, void* v)
  682. {
  683. iprint("badaddr %p\n", read_csr(sbadaddr));
  684. panic("double fault");
  685. }
  686. static void
  687. unexpected(Ureg *ureg, void* v)
  688. {
  689. iprint("unexpected trap %llu; ignoring\n", ureg->cause);
  690. }
  691. static void
  692. expected(Ureg* ureg, void* v)
  693. {
  694. }
  695. #endif
  696. /*static*/
  697. void
  698. faultarch(Ureg* ureg)
  699. {
  700. Proc *up = externup();
  701. uint64_t addr;
  702. int ftype = ureg->ftype, user, insyscall;
  703. char buf[ERRMAX];
  704. addr = ureg->badaddr;
  705. user = userureg(ureg);
  706. if(!user && mmukmapsync(addr))
  707. return;
  708. /*
  709. * There must be a user context.
  710. * If not, the usual problem is causing a fault during
  711. * initialisation before the system is fully up.
  712. */
  713. if(up == nil){
  714. panic("fault with up == nil; pc %#llx addr %#llx\n",
  715. ureg->ip, addr);
  716. }
  717. insyscall = up->insyscall;
  718. up->insyscall = 1;
  719. if (0) msg("call fault\n");
  720. if(fault(addr, ureg->ip, ftype) < 0){
  721. iprint("could not %s fault %p\n", faulttypes[ftype], addr);
  722. /*
  723. * It is possible to get here with !user if, for example,
  724. * a process was in a system call accessing a shared
  725. * segment but was preempted by another process which shrunk
  726. * or deallocated the shared segment; when the original
  727. * process resumes it may fault while in kernel mode.
  728. * No need to panic this case, post a note to the process
  729. * and unwind the error stack. There must be an error stack
  730. * (up->nerrlab != 0) if this is a system call, if not then
  731. * the game's a bogey.
  732. */
  733. if(!user && (!insyscall || up->nerrlab == 0))
  734. panic("fault: %#llx\n", addr);
  735. sprint(buf, "sys: trap: fault %s addr=%#llx",
  736. faulttypes[ftype], addr);
  737. postnote(up, 1, buf, NDebug);
  738. if(insyscall)
  739. error(buf);
  740. }
  741. up->insyscall = insyscall;
  742. }
  743. /*
  744. * return the userpc the last exception happened at
  745. */
  746. uintptr_t
  747. userpc(Ureg* ureg)
  748. {
  749. Proc *up = externup();
  750. if(ureg == nil)
  751. ureg = up->dbgreg;
  752. return ureg->ip;
  753. }
  754. /* This routine must save the values of registers the user is not permitted
  755. * to write from devproc and then restore the saved values before returning.
  756. * TODO: fix this because the segment registers are wrong for 64-bit mode.
  757. */
  758. void
  759. setregisters(Ureg* ureg, char* pureg, char* uva, int n)
  760. {
  761. #if 0
  762. uint64_t cs, flags, ss;
  763. ss = ureg->ss;
  764. flags = ureg->flags;
  765. cs = ureg->cs;
  766. memmove(pureg, uva, n);
  767. ureg->cs = cs;
  768. ureg->flags = (ureg->flags & 0x00ff) | (flags & 0xff00);
  769. ureg->ss = ss;
  770. #endif
  771. }
  772. /* Give enough context in the ureg to produce a kernel stack for
  773. * a sleeping process
  774. */
  775. void
  776. setkernur(Ureg* ureg, Proc* p)
  777. {
  778. ureg->ip = p->sched.pc;
  779. ureg->sp = p->sched.sp+BY2SE;
  780. }
  781. uintptr_t
  782. dbgpc(Proc *p)
  783. {
  784. Ureg *ureg;
  785. ureg = p->dbgreg;
  786. if(ureg == 0)
  787. return 0;
  788. return ureg->ip;
  789. }