acore.c.old 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include <tos.h>
  7. #include <pool.h>
  8. #include "amd64.h"
  9. #include "ureg.h"
  10. #include "io.h"
  11. /*
  12. * BUG:
  13. * The AC must not accept interrupts while in the kernel,
  14. * or we must be prepared for nesting them, which we are not.
  15. * This is important for note handling, because postnote()
  16. * assumes that it's ok to send an IPI to an AC, no matter its
  17. * state.
  18. *
  19. */
  20. void
  21. intrac(Proc *p)
  22. {
  23. Mach *ac;
  24. ac = p->ac;
  25. if(ac == nil){
  26. DBG("intrac: Proc.ac is nil. no ipi sent.\n");
  27. return;
  28. }
  29. /*
  30. * It's ok if the AC gets idle in the mean time.
  31. */
  32. DBG("intrac: ipi to cpu%d\n", ac->machno);
  33. apicipi(ac->apicno);
  34. }
  35. /*
  36. * Functions starting with ac... are run in the application core.
  37. * All other functions are run by the time-sharing cores.
  38. */
  39. typedef void (*APfunc)(void);
  40. extern int notify(Ureg*);
  41. extern void _acsysret(void);
  42. extern void _actrapret(void);
  43. static char *acnames[] = { "Ok", "Trap", "Syscall"};
  44. void
  45. acmmuswitch(void)
  46. {
  47. cr3put(machp()->pml4->pa);
  48. }
  49. void xactouser(u64int);
  50. void
  51. actouser(void)
  52. {
  53. uintptr sp;
  54. Ureg *u;
  55. memmove(&sp, m->icc->data, sizeof(sp));
  56. u = m->proc->dbgreg;
  57. DBG("cpu%d: touser usp = %#p entry %#p\n", machp()->machno, sp, u->ip);
  58. /*
  59. * This code for updating tos is wrong. It shouldn't go here.
  60. * It's the fact that we assing a process to a core what makes
  61. * it run in that core, not the fact that we call actouser(),
  62. * In the future, we might not even call actouser here. -Nemo.
  63. */
  64. /* BUG: add a function, called here and kexit */
  65. m->load = 100;
  66. xactouser(sp);
  67. panic("actouser");
  68. }
  69. void
  70. actrapret(void)
  71. {
  72. /* done by actrap() */
  73. }
  74. /*
  75. * Entered in AP core context, upon traps and system calls.
  76. * using up->dbgreg means cores MUST be homogeneous.
  77. */
  78. void
  79. actrap(Ureg *u)
  80. {
  81. /* print instead of DBG, so we see any trap by now */
  82. switch(u->type){
  83. case IdtIPI:
  84. m->intr++;
  85. print("actrap: cpu%d: IPI\n", machp()->machno);
  86. /*
  87. * Beware: BUG: we can get now IPIs while in kernel mode,
  88. * after declaring the end of the interrupt.
  89. * The code is not prepared for that.
  90. */
  91. apiceoi(IdtIPI);
  92. break;
  93. case IdtPF:
  94. m->pfault++;
  95. print("actrap: cpu%d: PF\n", machp()->machno);
  96. break;
  97. default:
  98. print("actrap: cpu%d: %ulld\n", machp()->machno, u->type);
  99. }
  100. m->icc->rc = ICCTRAP;
  101. m->cr2 = cr2get();
  102. memmove(m->proc->dbgreg, u, sizeof *u);
  103. m->icc->fn = nil;
  104. mfence();
  105. ready(m->proc);
  106. m->load = 0;
  107. while(*m->icc->fn == nil)
  108. ;
  109. m->load = 100;
  110. if(m->icc->flushtlb)
  111. acmmuswitch();
  112. DBG("actrap: ret\n");
  113. if(m->icc->fn != actrapret)
  114. acsched();
  115. memmove(u, m->proc->dbgreg, sizeof *u);
  116. }
  117. void
  118. acsyscall(void)
  119. {
  120. /*
  121. * If we saved the Ureg into m->proc->dbgregs,
  122. * There's nothing else we have to do.
  123. * Otherwise, we should m->proc->dbgregs = u;
  124. */
  125. DBG("acsyscall: cpu%d\n", machp()->machno);
  126. m->syscall++; /* would also count it in the TS core */
  127. m->icc->rc = ICCSYSCALL;
  128. m->cr2 = cr2get();
  129. m->icc->fn = nil;
  130. ready(m->proc);
  131. m->load = 0;
  132. /*
  133. * The next call is probably going to make us jmp
  134. * into user code, forgetting all our state in this
  135. * stack, upon the next syscall.
  136. * We don't nest calls in the current stack for too long.
  137. */
  138. acsched();
  139. }
  140. /*
  141. * Called in AP core context, to return from system call.
  142. */
  143. void
  144. acsysret(void)
  145. {
  146. DBG("acsysret\n");
  147. _acsysret();
  148. }
  149. void
  150. dumpreg(void *u)
  151. {
  152. print("reg is %p\n", u);
  153. ndnr();
  154. }
  155. /*
  156. * run an arbitrary function with arbitrary args on an ap core
  157. * first argument is always pml4 for process
  158. * make a field and a struct for the args cache line.
  159. *
  160. * Returns the return-code for the ICC or -1 if the process was
  161. * interrupted while issuing the ICC.
  162. */
  163. int
  164. runac(int core, APfunc func, int flushtlb, void *a, long n)
  165. {
  166. Mach *mp;
  167. uchar *dpg, *spg;
  168. if (n > sizeof(mp->icc->data))
  169. panic("runac: args too long");
  170. if((mp = sys->machptr[core]) == nil || mp->online == 0)
  171. panic("Bad core");
  172. if(mp->proc != nil && mp->proc != up)
  173. panic("runapfunc: mach is busy with another proc?");
  174. memmove(mp->icc->data, a, n);
  175. if(flushtlb){
  176. dpg = UINT2PTR(mp->pml4->va);
  177. spg = UINT2PTR(machp()->pml4->va);
  178. /* We should copy only user space mappings:
  179. * memmove(dgp, spg, machp()->pml4->daddr * sizeof(PTE));
  180. */
  181. memmove(dpg, spg, PTPGSZ);
  182. }
  183. mp->icc->flushtlb = flushtlb;
  184. mp->icc->rc = ICCOK;
  185. DBG("runac: exotic proc on cpu%d\n", mp->machno);
  186. if(waserror()){
  187. qunlock(&up->debug);
  188. nexterror();
  189. }
  190. qlock(&up->debug);
  191. up->ac = mp;
  192. up->nicc++;
  193. up->state = Exotic;
  194. up->psstate = 0;
  195. qunlock(&up->debug);
  196. poperror();
  197. mfence();
  198. mp->icc->fn = func;
  199. sched();
  200. return mp->icc->rc;
  201. }
  202. /*
  203. * Cleanup done by runacore to pretend we are going back to user space.
  204. * We won't return and won't do what syscall() would normally do.
  205. * Do it here instead.
  206. */
  207. static void
  208. fakeretfromsyscall(Ureg *ureg)
  209. {
  210. int s;
  211. poperror(); /* as syscall() would do if we would return */
  212. if(up->procctl == Proc_tracesyscall){ /* Would this work? */
  213. up->procctl = Proc_stopme;
  214. s = splhi();
  215. procctl(up);
  216. splx(s);
  217. }
  218. up->insyscall = 0;
  219. /* if we delayed sched because we held a lock, sched now */
  220. if(up->delaysched){
  221. sched();
  222. splhi();
  223. }
  224. kexit(ureg);
  225. }
  226. static void
  227. testproc(void *a)
  228. {
  229. Proc *p;
  230. p = a;
  231. if(p == nil){
  232. print("no proc to intr\n");
  233. return;
  234. }
  235. tsleep(&up->sleep, return0, 0, 10000);
  236. print("testproc: sending ipi to proc\n");
  237. intrac(p);
  238. print("sent\n");
  239. }
  240. /*
  241. * Move the current process to an application core.
  242. * This is performed at the end of execac(), and
  243. * we pretend to be returning to user-space, but instead we
  244. * dispatch the process to another core.
  245. * 1. We do the final bookkeeping that syscall() would do after
  246. * a return from sysexec(), because we are not returning.
  247. * 2. We dispatch the process to an AC using an ICC.
  248. *
  249. * This function won't return unless the process is reclaimed back
  250. * to the time-sharing core, and is the handler for the process
  251. * to deal with traps and system calls until the process dies.
  252. *
  253. * Remember that this function is the "line" between user and kernel
  254. * space, it's not expected to raise|handle any error.
  255. *
  256. * We install a safety error label, just in case we raise errors,
  257. * which we shouldn't. (noerrorsleft knows that for exotic processes
  258. * there is an error label pushed by us).
  259. */
  260. void
  261. runacore(int core, u64int ar0p)
  262. {
  263. Ureg *ureg;
  264. void (*fn)(void);
  265. int rc, flush, becometimesharing;
  266. if(waserror())
  267. panic("runacore: error: %s\n", up->errstr);
  268. ureg = up->dbgreg;
  269. ureg->ax = ar0p; /* see xactouser */
  270. fakeretfromsyscall(ureg);
  271. /* IPI testing */
  272. if(0)
  273. kproc("testproc", testproc, up);
  274. rc = runac(core, actouser, 1, &ureg->sp, sizeof ureg->sp);
  275. becometimesharing = 0;
  276. for(;;){
  277. flush = 0;
  278. fn = nil;
  279. switch(rc){
  280. case ICCTRAP:
  281. m->cr2 = up->ac->cr2;
  282. DBG("runacore: trap %ulld cr2 %#ullx ureg %#p\n",
  283. ureg->type, m->cr2, ureg);
  284. if(ureg->type == IdtIPI){
  285. if(up->procctl || up->nnote)
  286. notify(up->dbgreg);
  287. kexit(up->dbgreg);
  288. }else
  289. trap(ureg);
  290. flush = 1;
  291. fn = actrapret;
  292. break;
  293. case ICCSYSCALL:
  294. DBG("runacore: syscall ax %#ullx ureg %#p\n",
  295. ureg->ax, ureg);
  296. syscall(ureg->ax, ureg);
  297. flush = 1;
  298. fn = acsysret;
  299. break;
  300. default:
  301. panic("runacore: unexpected rc = %d", rc);
  302. }
  303. if(becometimesharing)
  304. break;
  305. rc = runac(core, fn, flush, &ureg, sizeof ureg);
  306. }
  307. fakeretfromsyscall(up->dbgreg);
  308. /*
  309. * dettach from the AC.
  310. */
  311. up->ac->proc = nil;
  312. up->ac = nil;
  313. /* And we return to syscall, which would do nothing but
  314. * returning, and we'd be back to the TS core.
  315. */
  316. }
  317. void
  318. acmodeset(int mode)
  319. {
  320. switch(mode){
  321. case NIXAC:
  322. case NIXKC:
  323. case NIXTC:
  324. break;
  325. default:
  326. panic("apmodeset: bad mode %d", mode);
  327. }
  328. m->nixtype = mode;
  329. }
  330. void
  331. stopac(Proc *p)
  332. {
  333. Mach *mp;
  334. mp = p->ac;
  335. if(mp == nil)
  336. return;
  337. if(mp->proc != p)
  338. return;
  339. DBG("stopac: cpu%d\n", mp->machno);
  340. p->ac = nil;
  341. mp->proc = nil;
  342. // send sipi to p->ac, it would rerun squidboy(), and
  343. // wait for us to give it a function to run.
  344. }
  345. void
  346. acinit(void)
  347. {
  348. /*
  349. * Lower the priority of the apic to 0,
  350. * to accept interrupts.
  351. * Raise it later if needed to disable them.
  352. */
  353. apicpri(0);
  354. }