trap.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  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 "amd64.h"
  20. // counters. Set by assembly code.
  21. // interrupt enter and exit, systecm call enter and exit.
  22. unsigned long ire, irx, sce, scx;
  23. // Did we start doing an exit for the interrupts?
  24. // ir exit entry :-)
  25. unsigned long irxe;
  26. extern int notify(Ureg*);
  27. static void debugbpt(Ureg*, void*);
  28. static void faultamd64(Ureg*, void*);
  29. static void doublefault(Ureg*, void*);
  30. static void unexpected(Ureg*, void*);
  31. static void expected(Ureg*, void*);
  32. static void dumpstackwithureg(Ureg*);
  33. extern int bus_irq_setup(Vctl*);
  34. static Lock vctllock;
  35. static Vctl *vctl[256];
  36. typedef struct Intrtime Intrtime;
  37. struct Intrtime {
  38. uint64_t count;
  39. uint64_t cycles;
  40. };
  41. static Intrtime intrtimes[256];
  42. void*
  43. intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
  44. {
  45. int vno;
  46. Vctl *v;
  47. if(f == nil){
  48. print("intrenable: nil handler for %d, tbdf %#x for %s\n",
  49. irq, tbdf, name);
  50. return nil;
  51. }
  52. v = malloc(sizeof(Vctl));
  53. v->isintr = 1;
  54. v->Vkey.irq = irq;
  55. v->Vkey.tbdf = tbdf;
  56. v->f = f;
  57. v->a = a;
  58. strncpy(v->name, name, KNAMELEN-1);
  59. v->name[KNAMELEN-1] = 0;
  60. ilock(&vctllock);
  61. vno = bus_irq_setup(v);
  62. if(vno == -1){
  63. iunlock(&vctllock);
  64. print("intrenable: couldn't enable irq %d, tbdf %#x for %s\n",
  65. irq, tbdf, v->name);
  66. free(v);
  67. return nil;
  68. }
  69. if(vctl[vno]){
  70. if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)
  71. panic("intrenable: handler: %s %s %#p %#p %#p %#p",
  72. vctl[v->vno]->name, v->name,
  73. vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);
  74. }
  75. v->vno = vno;
  76. v->next = vctl[vno];
  77. vctl[vno] = v;
  78. iunlock(&vctllock);
  79. if(v->mask)
  80. v->mask(&v->Vkey, 0);
  81. /*
  82. * Return the assigned vector so intrdisable can find
  83. * the handler; the IRQ is useless in the wonderful world
  84. * of the IOAPIC.
  85. */
  86. return v;
  87. }
  88. int acpiintrenable(Vctl *v)
  89. {
  90. int vno;
  91. ilock(&vctllock);
  92. vno = bus_irq_setup(v);
  93. if(vno == -1){
  94. iunlock(&vctllock);
  95. print("intrenable: couldn't enable irq %d, tbdf %#x for %s\n",
  96. v->Vkey.irq, v->Vkey.tbdf, v->name);
  97. free(v);
  98. return -1;
  99. }
  100. if(vctl[vno]){
  101. if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)
  102. panic("intrenable: handler: %s %s %#p %#p %#p %#p",
  103. vctl[v->vno]->name, v->name,
  104. vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);
  105. }
  106. v->vno = vno;
  107. v->next = vctl[vno];
  108. vctl[vno] = v;
  109. iunlock(&vctllock);
  110. if(v->mask)
  111. v->mask(&v->Vkey, 0);
  112. return -1;
  113. }
  114. int
  115. intrdisable(void* vector)
  116. {
  117. Vctl *v, *x, **ll;
  118. extern int ioapicintrdisable(int);
  119. ilock(&vctllock);
  120. v = vector;
  121. if(v == nil || vctl[v->vno] != v)
  122. panic("intrdisable: v %#p", v);
  123. for(ll = vctl+v->vno; x = *ll; ll = &x->next)
  124. if(v == x)
  125. break;
  126. if(x != v)
  127. panic("intrdisable: v %#p", v);
  128. if(v->mask)
  129. v->mask(&v->Vkey, 1);
  130. v->f(nil, v->a);
  131. *ll = v->next;
  132. ioapicintrdisable(v->vno);
  133. iunlock(&vctllock);
  134. free(v);
  135. return 0;
  136. }
  137. static int32_t
  138. irqmapread(Chan* c, void *vbuf, int32_t n, int64_t offset)
  139. {
  140. char *readtodo(void);
  141. return readstr(offset, vbuf, n, readtodo());
  142. }
  143. static int32_t
  144. irqmapwrite(Chan* c, void *buf, int32_t n, int64_t offset)
  145. {
  146. int acpiirq(uint32_t tbdf, int irq);
  147. int t, b, d, f, irq;
  148. int *p[] = {&t, &b, &d, &f, &irq};
  149. Cmdbuf *cb;
  150. cb = parsecmd(buf, n);
  151. if (cb->nf < nelem(p))
  152. error("iprqmapwrite t b d f irq");
  153. for(int i = 0; i < nelem(p); i++)
  154. *p[i] = strtoul(cb->f[i], 0, 0);
  155. acpiirq(MKBUS(t, b, d, f), irq);
  156. return -1;
  157. }
  158. static int32_t
  159. irqenablewrite(Chan* c, void *vbuf, int32_t n, int64_t offset)
  160. {
  161. void irqenable(void);
  162. irqenable();
  163. return n;
  164. }
  165. static int32_t
  166. irqallocread(Chan* c, void *vbuf, int32_t n, int64_t offset)
  167. {
  168. char *buf, *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1];
  169. int m, vno;
  170. int32_t oldn;
  171. Intrtime *t;
  172. Vctl *v;
  173. if(n < 0 || offset < 0)
  174. error(Ebadarg);
  175. oldn = n;
  176. buf = vbuf;
  177. for(vno=0; vno<nelem(vctl); vno++){
  178. for(v=vctl[vno]; v; v=v->next){
  179. t = intrtimes + vno;
  180. m = snprint(str, sizeof str, "%11d %11d %20llu %20llu %-*.*s %.*s\n",
  181. vno, v->Vkey.irq, t->count, t->cycles, 8, 8, v->type, KNAMELEN, v->name);
  182. if(m <= offset) /* if do not want this, skip entry */
  183. offset -= m;
  184. else{
  185. /* skip offset bytes */
  186. m -= offset;
  187. p = str+offset;
  188. offset = 0;
  189. /* write at most max(n,m) bytes */
  190. if(m > n)
  191. m = n;
  192. memmove(buf, p, m);
  193. n -= m;
  194. buf += m;
  195. if(n == 0)
  196. return oldn;
  197. }
  198. }
  199. }
  200. return oldn - n;
  201. }
  202. void
  203. trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
  204. {
  205. Vctl *v;
  206. if(vno < 0 || vno >= 256)
  207. panic("trapenable: vno %d\n", vno);
  208. v = malloc(sizeof(Vctl));
  209. v->type = "trap";
  210. v->Vkey.tbdf = BUSUNKNOWN;
  211. v->f = f;
  212. v->a = a;
  213. strncpy(v->name, name, KNAMELEN);
  214. v->name[KNAMELEN-1] = 0;
  215. ilock(&vctllock);
  216. v->next = vctl[vno];
  217. vctl[vno] = v;
  218. iunlock(&vctllock);
  219. }
  220. static void
  221. nmienable(void)
  222. {
  223. int x;
  224. /*
  225. * Hack: should be locked with NVRAM access.
  226. */
  227. outb(0x70, 0x80); /* NMI latch clear */
  228. outb(0x70, 0);
  229. x = inb(0x61) & 0x07; /* Enable NMI */
  230. outb(0x61, 0x08|x);
  231. outb(0x61, x);
  232. }
  233. void
  234. trapinit(void)
  235. {
  236. /*
  237. * Need to set BPT interrupt gate - here or in vsvminit?
  238. */
  239. /*
  240. * Special traps.
  241. * Syscall() is called directly without going through trap().
  242. */
  243. trapenable(VectorBPT, debugbpt, 0, "#BP");
  244. trapenable(VectorPF, faultamd64, 0, "#PF");
  245. trapenable(Vector2F, doublefault, 0, "#DF");
  246. intrenable(IdtIPI, expected, 0, BUSUNKNOWN, "#IPI");
  247. trapenable(Vector15, unexpected, 0, "#15");
  248. nmienable();
  249. addarchfile("irqalloc", 0444, irqallocread, nil);
  250. addarchfile("irqmap", 0666, irqmapread, irqmapwrite);
  251. addarchfile("irqenable", 0222, nil, irqenablewrite);
  252. }
  253. static char* excname[32] = {
  254. "#DE", /* Divide-by-Zero Error */
  255. "#DB", /* Debug */
  256. "#NMI", /* Non-Maskable-Interrupt */
  257. "#BP", /* Breakpoint */
  258. "#OF", /* Overflow */
  259. "#BR", /* Bound-Range */
  260. "#UD", /* Invalid-Opcode */
  261. "#NM", /* Device-Not-Available */
  262. "#DF", /* Double-Fault */
  263. "#9 (reserved)",
  264. "#TS", /* Invalid-TSS */
  265. "#NP", /* Segment-Not-Present */
  266. "#SS", /* Stack */
  267. "#GP", /* General-Protection */
  268. "#PF", /* Page-Fault */
  269. "#15 (reserved)",
  270. "#MF", /* x87 FPE-Pending */
  271. "#AC", /* Alignment-Check */
  272. "#MC", /* Machine-Check */
  273. "#XF", /* SIMD Floating-Point */
  274. "#20 (reserved)",
  275. "#21 (reserved)",
  276. "#22 (reserved)",
  277. "#23 (reserved)",
  278. "#24 (reserved)",
  279. "#25 (reserved)",
  280. "#26 (reserved)",
  281. "#27 (reserved)",
  282. "#28 (reserved)",
  283. "#29 (reserved)",
  284. "#30 (reserved)",
  285. "#31 (reserved)",
  286. };
  287. /*
  288. * keep interrupt service times and counts
  289. */
  290. void
  291. intrtime(int vno)
  292. {
  293. Proc *up = externup();
  294. uint32_t diff, x; /* should be uint64_t */
  295. x = perfticks();
  296. diff = x - machp()->perf.intrts;
  297. machp()->perf.intrts = x;
  298. machp()->perf.inintr += diff;
  299. if(up == nil && machp()->perf.inidle > diff)
  300. machp()->perf.inidle -= diff;
  301. intrtimes[vno].cycles += diff;
  302. intrtimes[vno].count++;
  303. }
  304. static void
  305. pmcnop(Mach *m)
  306. {
  307. }
  308. void (*_pmcupdate)(Mach *m) = pmcnop;
  309. /* go to user space */
  310. void
  311. kexit(Ureg* u)
  312. {
  313. Proc *up = externup();
  314. uint64_t t;
  315. Tos *tos;
  316. Mach *mp;
  317. /*
  318. * precise time accounting, kernel exit
  319. * initialized in exec, sysproc.c
  320. */
  321. tos = (Tos*)(USTKTOP-sizeof(Tos));
  322. cycles(&t);
  323. tos->kcycles += t - up->kentry;
  324. tos->pcycles = up->pcycles;
  325. tos->pid = up->pid;
  326. if (up->ac != nil)
  327. mp = up->ac;
  328. else
  329. mp = machp();
  330. tos->core = mp->machno;
  331. tos->nixtype = mp->NIX.nixtype;
  332. //_pmcupdate(m);
  333. /*
  334. * The process may change its core.
  335. * Be sure it has the right cyclefreq.
  336. */
  337. tos->cyclefreq = mp->cyclefreq;
  338. /* thread local storage */
  339. wrmsr(FSbase, up->tls);
  340. }
  341. void
  342. kstackok(void)
  343. {
  344. Proc *up = externup();
  345. if(up == nil){
  346. uintptr_t *stk = (uintptr_t*)machp()->stack;
  347. if(*stk != STACKGUARD)
  348. panic("trap: mach %d machstk went through bottom %p\n", machp()->machno, machp()->stack);
  349. } else {
  350. uintptr_t *stk = (uintptr_t*)up->kstack;
  351. if(*stk != STACKGUARD)
  352. panic("trap: proc %d kstack went through bottom %p\n", up->pid, up->kstack);
  353. }
  354. }
  355. void
  356. _trap(Ureg *ureg)
  357. {
  358. /*
  359. * If it's a real trap in this core, then we want to
  360. * use the hardware cr2 register.
  361. * We cannot do this in trap() because application cores
  362. * would update m->cr2 with their cr2 values upon page faults,
  363. * and then call trap().
  364. * If we do this in trap(), we would overwrite that with our own cr2.
  365. */
  366. if(ureg->type == VectorPF)
  367. machp()->MMU.cr2 = cr2get();
  368. trap(ureg);
  369. }
  370. static int lastvno;
  371. /*
  372. * All traps come here. It is slower to have all traps call trap()
  373. * rather than directly vectoring the handler. However, this avoids a
  374. * lot of code duplication and possible bugs. The only exception is
  375. * VectorSYSCALL.
  376. * Trap is called with interrupts disabled via interrupt-gates.
  377. */
  378. void
  379. trap(Ureg* ureg)
  380. {
  381. int clockintr, vno, user;
  382. // cache the previous vno to see what might be causing
  383. // trouble
  384. vno = ureg->type;
  385. uint64_t gsbase = rdmsr(GSbase);
  386. //if (sce > scx) iprint("====================");
  387. lastvno = vno;
  388. if (gsbase < 1ULL<<63)
  389. die("bogus gsbase");
  390. Proc *up = externup();
  391. char buf[ERRMAX];
  392. Vctl *ctl, *v;
  393. machp()->perf.intrts = perfticks();
  394. user = userureg(ureg);
  395. if(user && (machp()->NIX.nixtype == NIXTC)){
  396. up->dbgreg = ureg;
  397. cycles(&up->kentry);
  398. }
  399. clockintr = 0;
  400. //_pmcupdate(machp());
  401. if(ctl = vctl[vno]){
  402. if(ctl->isintr){
  403. machp()->intr++;
  404. if(vno >= VectorPIC && vno != VectorSYSCALL)
  405. machp()->lastintr = ctl->Vkey.irq;
  406. }else
  407. if(up)
  408. up->nqtrap++;
  409. if(ctl->isr){
  410. ctl->isr(vno);
  411. if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr);
  412. }
  413. for(v = ctl; v != nil; v = v->next){
  414. if(v->f){
  415. v->f(ureg, v->a);
  416. if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f);
  417. }
  418. }
  419. if(ctl->eoi){
  420. ctl->eoi(vno);
  421. if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi);
  422. }
  423. intrtime(vno);
  424. if(ctl->isintr){
  425. if(ctl->Vkey.irq == IrqCLOCK || ctl->Vkey.irq == IrqTIMER)
  426. clockintr = 1;
  427. if (ctl->Vkey.irq == IrqTIMER)
  428. oprof_alarm_handler(ureg);
  429. if(up && !clockintr)
  430. preempted();
  431. }
  432. }
  433. else if(vno < nelem(excname) && user){
  434. spllo();
  435. snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
  436. postnote(up, 1, buf, NDebug);
  437. }
  438. else if(vno >= VectorPIC && vno != VectorSYSCALL){
  439. /*
  440. * An unknown interrupt.
  441. * Check for a default IRQ7. This can happen when
  442. * the IRQ input goes away before the acknowledge.
  443. * In this case, a 'default IRQ7' is generated, but
  444. * the corresponding bit in the ISR isn't set.
  445. * In fact, just ignore all such interrupts.
  446. */
  447. /* clear the interrupt */
  448. i8259isr(vno);
  449. iprint("cpu%d: spurious interrupt %d, last %d\n",
  450. machp()->machno, vno, machp()->lastintr);
  451. intrtime(vno);
  452. if(user)
  453. kexit(ureg);
  454. return;
  455. }
  456. else{
  457. if(vno == VectorNMI){
  458. nmienable();
  459. if(machp()->machno != 0){
  460. iprint("cpu%d: PC %#llx\n",
  461. machp()->machno, ureg->ip);
  462. for(;;);
  463. }
  464. }
  465. dumpregs(ureg);
  466. if(!user){
  467. ureg->sp = PTR2UINT(&ureg->sp);
  468. dumpstackwithureg(ureg);
  469. }
  470. if(vno < nelem(excname))
  471. panic("%s", excname[vno]);
  472. panic("unknown trap/intr: %d\n", vno);
  473. }
  474. splhi();
  475. /* delaysched set because we held a lock or because our quantum ended */
  476. if(up && up->delaysched && clockintr){
  477. if(0)
  478. if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0){
  479. if(!waserror()){
  480. up->ac = getac(up, -1);
  481. poperror();
  482. runacore();
  483. return;
  484. }
  485. }
  486. sched();
  487. splhi();
  488. }
  489. if(user){
  490. if(up && up->procctl || up->nnote)
  491. notify(ureg);
  492. kexit(ureg);
  493. }
  494. }
  495. /*
  496. * Dump general registers.
  497. */
  498. void
  499. dumpgpr(Ureg* ureg)
  500. {
  501. Proc *up = externup();
  502. if(up != nil)
  503. print("cpu%d: registers for %s %d\n",
  504. machp()->machno, up->text, up->pid);
  505. else
  506. print("cpu%d: registers for kernel\n", machp()->machno);
  507. print("ax\t%#16.16llx\n", ureg->ax);
  508. print("bx\t%#16.16llx\n", ureg->bx);
  509. print("cx\t%#16.16llx\n", ureg->cx);
  510. print("dx\t%#16.16llx\n", ureg->dx);
  511. print("di\t%#16.16llx\n", ureg->di);
  512. print("si\t%#16.16llx\n", ureg->si);
  513. print("bp\t%#16.16llx\n", ureg->bp);
  514. print("r8\t%#16.16llx\n", ureg->r8);
  515. print("r9\t%#16.16llx\n", ureg->r9);
  516. print("r10\t%#16.16llx\n", ureg->r10);
  517. print("r11\t%#16.16llx\n", ureg->r11);
  518. print("r12\t%#16.16llx\n", ureg->r12);
  519. print("r13\t%#16.16llx\n", ureg->r13);
  520. print("r14\t%#16.16llx\n", ureg->r14);
  521. print("r15\t%#16.16llx\n", ureg->r15);
  522. print("type\t%#llx\n", ureg->type);
  523. print("error\t%#llx\n", ureg->error);
  524. print("pc\t%#llx\n", ureg->ip);
  525. print("cs\t%#llx\n", ureg->cs);
  526. print("flags\t%#llx\n", ureg->flags);
  527. print("sp\t%#llx\n", ureg->sp);
  528. print("ss\t%#llx\n", ureg->ss);
  529. print("type\t%#llx\n", ureg->type);
  530. print("FS\t%#llx\n", rdmsr(FSbase));
  531. print("GS\t%#llx\n", rdmsr(GSbase));
  532. print("m\t%#16.16p\nup\t%#16.16p\n", machp(), up);
  533. }
  534. void
  535. dumpregs(Ureg* ureg)
  536. {
  537. die("dumpregs");
  538. dumpgpr(ureg);
  539. /*
  540. * Processor control registers.
  541. * If machine check exception, time stamp counter, page size extensions
  542. * or enhanced virtual 8086 mode extensions are supported, there is a
  543. * CR4. If there is a CR4 and machine check extensions, read the machine
  544. * check address and machine check type registers if RDMSR supported.
  545. */
  546. print("cr0\t%#16.16llx\n", cr0get());
  547. print("cr2\t%#16.16llx\n", machp()->MMU.cr2);
  548. print("cr3\t%#16.16llx\n", cr3get());
  549. die("dumpregs");
  550. // archdumpregs();
  551. }
  552. /*
  553. * Fill in enough of Ureg to get a stack trace, and call a function.
  554. * Used by debugging interface rdb.
  555. */
  556. void
  557. callwithureg(void (*fn)(Ureg*))
  558. {
  559. Ureg ureg;
  560. ureg.ip = getcallerpc(&fn);
  561. ureg.sp = PTR2UINT(&fn);
  562. fn(&ureg);
  563. }
  564. static void
  565. dumpstackwithureg(Ureg* ureg)
  566. {
  567. Proc *up = externup();
  568. uintptr_t l, v, i, estack;
  569. // extern char etext;
  570. int x;
  571. if (0) { //if((s = getconf("*nodumpstack")) != nil && atoi(s) != 0){
  572. iprint("dumpstack disabled\n");
  573. return;
  574. }
  575. iprint("dumpstack\n");
  576. x = 0;
  577. x += iprint("ktrace 9%s %#p %#p\n", strrchr(conffile, '/')+1, ureg->ip, ureg->sp);
  578. i = 0;
  579. if(up != nil
  580. // && (uintptr)&l >= (uintptr)up->kstack
  581. && (uintptr_t)&l <= (uintptr_t)up->kstack+KSTACK)
  582. estack = (uintptr_t)up->kstack+KSTACK;
  583. else if((uintptr_t)&l >= machp()->stack && (uintptr_t)&l <= machp()->stack+MACHSTKSZ)
  584. estack = machp()->stack+MACHSTKSZ;
  585. else{
  586. if(up != nil)
  587. iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
  588. else
  589. iprint("&m %#p &l %#p\n", machp(), &l);
  590. return;
  591. }
  592. x += iprint("estackx %#p\n", estack);
  593. for(l = (uintptr_t)&l; l < estack; l += sizeof(uintptr_t)){
  594. v = *(uintptr_t*)l;
  595. if((KTZERO < v && v < (uintptr_t)&etext)
  596. || ((uintptr_t)&l < v && v < estack) || estack-l < 256){
  597. x += iprint("%#16.16p=%#16.16p ", l, v);
  598. i++;
  599. }
  600. if(i == 2){
  601. i = 0;
  602. x += iprint("\n");
  603. }
  604. }
  605. if(i)
  606. iprint("\n");
  607. }
  608. void
  609. dumpstack(void)
  610. {
  611. callwithureg(dumpstackwithureg);
  612. }
  613. static void
  614. debugbpt(Ureg* ureg, void* v)
  615. {
  616. Proc *up = externup();
  617. char buf[ERRMAX];
  618. if(up == 0)
  619. panic("kernel bpt");
  620. /* restore pc to instruction that caused the trap */
  621. ureg->ip--;
  622. sprint(buf, "sys: breakpoint");
  623. postnote(up, 1, buf, NDebug);
  624. }
  625. static void
  626. doublefault(Ureg* ureg, void* v)
  627. {
  628. iprint("cr2 %p\n", (void *)cr2get());
  629. panic("double fault");
  630. }
  631. static void
  632. unexpected(Ureg* ureg, void* v)
  633. {
  634. iprint("unexpected trap %llu; ignoring\n", ureg->type);
  635. }
  636. static void
  637. expected(Ureg* ureg, void* v)
  638. {
  639. }
  640. static void
  641. faultamd64(Ureg* ureg, void* v)
  642. {
  643. Proc *up = externup();
  644. uint64_t addr;
  645. int ftype, user, insyscall;
  646. char buf[ERRMAX];
  647. addr = machp()->MMU.cr2;
  648. user = userureg(ureg);
  649. if(!user && mmukmapsync(addr))
  650. return;
  651. /*
  652. * There must be a user context.
  653. * If not, the usual problem is causing a fault during
  654. * initialisation before the system is fully up.
  655. */
  656. if(up == nil){
  657. panic("fault with up == nil; pc %#llx addr %#llx\n",
  658. ureg->ip, addr);
  659. }
  660. ftype = (ureg->error&2) ? FT_WRITE : (ureg->error&16) ? FT_EXEC : FT_READ;
  661. /*
  662. if (read) hi("read fault\n"); else hi("write fault\n");
  663. hi("addr "); put64(addr); hi("\n");
  664. */
  665. insyscall = up->insyscall;
  666. up->insyscall = 1;
  667. if (0)hi("call fault\n");
  668. if(fault(addr, ureg->ip, ftype) < 0){
  669. iprint("could not %s fault %p\n", faulttypes[ftype], addr);
  670. /*
  671. * It is possible to get here with !user if, for example,
  672. * a process was in a system call accessing a shared
  673. * segment but was preempted by another process which shrunk
  674. * or deallocated the shared segment; when the original
  675. * process resumes it may fault while in kernel mode.
  676. * No need to panic this case, post a note to the process
  677. * and unwind the error stack. There must be an error stack
  678. * (up->nerrlab != 0) if this is a system call, if not then
  679. * the game's a bogey.
  680. */
  681. if(!user && (!insyscall || up->nerrlab == 0))
  682. panic("fault: %#llx\n", addr);
  683. sprint(buf, "sys: trap: fault %s addr=%#llx",
  684. faulttypes[ftype], addr);
  685. postnote(up, 1, buf, NDebug);
  686. if(insyscall)
  687. error(buf);
  688. }
  689. up->insyscall = insyscall;
  690. }
  691. /*
  692. * return the userpc the last exception happened at
  693. */
  694. uintptr_t
  695. userpc(Ureg* ureg)
  696. {
  697. Proc *up = externup();
  698. if(ureg == nil)
  699. ureg = up->dbgreg;
  700. return ureg->ip;
  701. }
  702. /* This routine must save the values of registers the user is not permitted
  703. * to write from devproc and then restore the saved values before returning.
  704. * TODO: fix this because the segment registers are wrong for 64-bit mode.
  705. */
  706. void
  707. setregisters(Ureg* ureg, char* pureg, char* uva, int n)
  708. {
  709. uint64_t cs, flags, ss;
  710. ss = ureg->ss;
  711. flags = ureg->flags;
  712. cs = ureg->cs;
  713. memmove(pureg, uva, n);
  714. ureg->cs = cs;
  715. ureg->flags = (ureg->flags & 0x00ff) | (flags & 0xff00);
  716. ureg->ss = ss;
  717. }
  718. /* Give enough context in the ureg to produce a kernel stack for
  719. * a sleeping process
  720. */
  721. void
  722. setkernur(Ureg* ureg, Proc* p)
  723. {
  724. ureg->ip = p->sched.pc;
  725. ureg->sp = p->sched.sp+BY2SE;
  726. }
  727. uintptr_t
  728. dbgpc(Proc *p)
  729. {
  730. Ureg *ureg;
  731. ureg = p->dbgreg;
  732. if(ureg == 0)
  733. return 0;
  734. return ureg->ip;
  735. }