tcore.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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 <tos.h>
  15. #include <pool.h>
  16. #include "ureg.h"
  17. #include "io.h"
  18. Lock nixaclock; /* NIX AC lock; held while assigning procs to cores */
  19. /*
  20. * NIX support for the time sharing core.
  21. */
  22. extern void actrapret(void);
  23. extern void acsysret(void);
  24. Mach*
  25. getac(Proc *p, int core)
  26. {
  27. Proc *up = externup();
  28. int i;
  29. Mach *mp;
  30. mp = nil;
  31. if(core == 0)
  32. panic("can't getac for a %s", rolename[NIXTC]);
  33. lock(&nixaclock);
  34. if(waserror()){
  35. unlock(&nixaclock);
  36. nexterror();
  37. }
  38. if(core > 0){
  39. if(core >= MACHMAX)
  40. error("no such core");
  41. mp = sys->machptr[core];
  42. if(mp == nil || mp->online == 0 || mp->proc != nil)
  43. error("core not online or busy");
  44. if(mp->NIX.nixtype != NIXAC)
  45. error("core is not an AC");
  46. Found:
  47. mp->proc = p;
  48. }else{
  49. for(i = 0; i < MACHMAX; i++)
  50. if((mp = sys->machptr[i]) != nil && mp->online && mp->NIX.nixtype == NIXAC)
  51. if(mp->proc == nil)
  52. goto Found;
  53. error("not enough cores");
  54. }
  55. unlock(&nixaclock);
  56. poperror();
  57. return mp;
  58. }
  59. /*
  60. * BUG:
  61. * The AC must not accept interrupts while in the kernel,
  62. * or we must be prepared for nesting them, which we are not.
  63. * This is important for note handling, because postnote()
  64. * assumes that it's ok to send an IPI to an AC, no matter its
  65. * state. The /proc interface also assumes that.
  66. *
  67. */
  68. void
  69. intrac(Proc *p)
  70. {
  71. Mach *ac;
  72. ac = p->ac;
  73. if(ac == nil){
  74. DBG("intrac: Proc.ac is nil. no ipi sent.\n");
  75. return;
  76. }
  77. /*
  78. * It's ok if the AC gets idle in the mean time.
  79. */
  80. DBG("intrac: ipi to cpu%d\n", ac->machno);
  81. // what to do?
  82. panic((char *)__func__);
  83. //apicipi(ac->apicno);
  84. }
  85. void
  86. putac(Mach *m)
  87. {
  88. mfence();
  89. m->proc = nil;
  90. }
  91. void
  92. stopac(void)
  93. {
  94. Proc *up = externup();
  95. Mach *mp;
  96. mp = up->ac;
  97. if(mp == nil)
  98. return;
  99. if(mp->proc != up)
  100. panic("stopac");
  101. lock(&nixaclock);
  102. up->ac = nil;
  103. mp->proc = nil;
  104. unlock(&nixaclock);
  105. /* TODO:
  106. * send sipi to up->ac, it would rerun squidboy(), and
  107. * wait for us to give it a function to run.
  108. */
  109. }
  110. /*
  111. * Functions starting with ac... are run in the application core.
  112. * All other functions are run by the time-sharing cores.
  113. */
  114. typedef void (*APfunc)(void);
  115. extern int notify(Ureg*);
  116. /*
  117. * run an arbitrary function with arbitrary args on an ap core
  118. * first argument is always root for process
  119. * make a field and a struct for the args cache line.
  120. *
  121. * Returns the return-code for the ICC or -1 if the process was
  122. * interrupted while issuing the ICC.
  123. */
  124. int
  125. runac(Mach *mp, APfunc func, int flushtlb, void *a, int32_t n)
  126. {
  127. Proc *up = externup();
  128. uint8_t *dpg, *spg;
  129. if (n > sizeof(mp->NIX.icc->data))
  130. panic("runac: args too long");
  131. if(mp->online == 0)
  132. panic("Bad core");
  133. if(mp->proc != nil && mp->proc != up)
  134. panic("runapfunc: mach is busy with another proc?");
  135. memmove(mp->NIX.icc->data, a, n);
  136. if(flushtlb){
  137. DBG("runac flushtlb: cproot %#p %#p\n", mp->MMU.root->pa, machp()->MMU.root->pa);
  138. dpg = UINT2PTR(mp->MMU.root->va);
  139. spg = UINT2PTR(machp()->MMU.root->va);
  140. /* We should copy less:
  141. * memmove(dgp, spg, machp()->MMU.root->daddr * sizeof(PTE));
  142. */
  143. memmove(dpg, spg, PTSZ);
  144. if(0){
  145. print("runac: upac root %#p\n", up->ac->MMU.root->pa);
  146. dumpptepg(4, up->ac->MMU.root->pa);
  147. }
  148. }
  149. mp->NIX.icc->flushtlb = flushtlb;
  150. mp->NIX.icc->rc = ICCOK;
  151. DBG("runac: exotic proc on cpu%d\n", mp->machno);
  152. if(waserror()){
  153. qunlock(&up->debug);
  154. nexterror();
  155. }
  156. qlock(&up->debug);
  157. up->nicc++;
  158. up->state = Exotic;
  159. up->psstate = 0;
  160. qunlock(&up->debug);
  161. poperror();
  162. mfence();
  163. mp->NIX.icc->fn = func;
  164. sched();
  165. return mp->NIX.icc->rc;
  166. }
  167. /*
  168. * Cleanup done by runacore to pretend we are going back to user space.
  169. * We won't return and won't do what syscall() would normally do.
  170. * Do it here instead.
  171. */
  172. static void
  173. fakeretfromsyscall(Ureg *ureg)
  174. {
  175. Proc *up = externup();
  176. int s;
  177. poperror(); /* as syscall() would do if we would return */
  178. if(up->procctl == Proc_tracesyscall){ /* Would this work? */
  179. up->procctl = Proc_stopme;
  180. s = splhi();
  181. procctl(up);
  182. splx(s);
  183. }
  184. up->insyscall = 0;
  185. /* if we delayed sched because we held a lock, sched now */
  186. if(up->delaysched){
  187. sched();
  188. splhi();
  189. }
  190. kexit(ureg);
  191. }
  192. /*
  193. * Move the current process to an application core.
  194. * This is performed at the end of execac(), and
  195. * we pretend to be returning to user-space, but instead we
  196. * dispatch the process to another core.
  197. * 1. We do the final bookkeeping that syscall() would do after
  198. * a return from sysexec(), because we are not returning.
  199. * 2. We dispatch the process to an AC using an ICC.
  200. *
  201. * This function won't return unless the process is reclaimed back
  202. * to the time-sharing core, and is the handler for the process
  203. * to deal with traps and system calls until the process dies.
  204. *
  205. * Remember that this function is the "line" between user and kernel
  206. * space, it's not expected to raise|handle any error.
  207. *
  208. * We install a safety error label, just in case we raise errors,
  209. * which we shouldn't. (noerrorsleft knows that for exotic processes
  210. * there is an error label pushed by us).
  211. */
  212. void
  213. runacore(void)
  214. {
  215. Proc *up = externup();
  216. Ureg *ureg;
  217. void (*fn)(void);
  218. int rc, flush, s;
  219. //char *n;
  220. uint64_t t1;
  221. if(waserror())
  222. panic("runacore: error: %s\n", up->errstr);
  223. ureg = up->dbgreg;
  224. fakeretfromsyscall(ureg);
  225. fpusysrfork(ureg);
  226. procpriority(up, PriKproc, 1);
  227. rc = runac(up->ac, actouser, 1, nil, 0);
  228. procpriority(up, PriNormal, 0);
  229. for(;;){
  230. t1 = fastticks(nil);
  231. flush = 0;
  232. fn = nil;
  233. switch(rc){
  234. case ICCTRAP:
  235. s = splhi();
  236. panic("cr2");
  237. //machp()->MMU.cr2 = up->ac->MMU.cr2;
  238. //DBG("runacore: trap %llu cr2 %#llx ureg %#p\n",
  239. //ureg->type, machp()->MMU.cr2, ureg);
  240. #if 0
  241. switch(ureg->type){
  242. case IdtIPI:
  243. if(up->procctl || up->nnote)
  244. notify(up->dbgreg);
  245. if(up->ac == nil)
  246. goto ToTC;
  247. kexit(up->dbgreg);
  248. break;
  249. case IdtNM:
  250. case IdtMF:
  251. case IdtXF:
  252. /* these are handled in the AC;
  253. * If we get here, they left in m->NIX.icc->data
  254. * a note to be posted to the process.
  255. * Post it, and make the vector a NOP.
  256. */
  257. n = up->ac->NIX.icc->note;
  258. if(n != nil)
  259. postnote(up, 1, n, NDebug);
  260. ureg->type = IdtIPI; /* NOP */
  261. break;
  262. default:
  263. rootput(machp()->MMU.root->pa);
  264. if(0 && ureg->type == IdtPF){
  265. print("before PF:\n");
  266. print("AC:\n");
  267. dumpptepg(4, up->ac->MMU.root->pa);
  268. print("\n%s:\n", rolename[NIXTC]);
  269. dumpptepg(4, machp()->MMU.root->pa);
  270. }
  271. trap(ureg);
  272. }
  273. #endif
  274. splx(s);
  275. flush = 1;
  276. fn = actrapret;
  277. break;
  278. case ICCSYSCALL:
  279. DBG("runacore: syscall a0 %#llx ureg %#p\n",
  280. ureg->a0, ureg);
  281. rootput(machp()->MMU.root->pa);
  282. //syscall(ureg->ax, ureg);
  283. flush = 1;
  284. fn = acsysret;
  285. if(0)
  286. if(up->nqtrap > 2 || up->nsyscall > 1)
  287. goto ToTC;
  288. if(up->ac == nil)
  289. goto ToTC;
  290. break;
  291. default:
  292. panic("runacore: unexpected rc = %d", rc);
  293. }
  294. up->tctime += fastticks2us(fastticks(nil) - t1);
  295. procpriority(up, PriExtra, 1);
  296. rc = runac(up->ac, fn, flush, nil, 0);
  297. procpriority(up, PriNormal, 0);
  298. }
  299. ToTC:
  300. /*
  301. * to procctl, then syscall, to
  302. * be back in the TC
  303. */
  304. DBG("runacore: up %#p: return\n", up);
  305. }
  306. extern ACVctl *acvctl[];
  307. void
  308. actrapenable(int vno, char* (*f)(Ureg*, void*), void* a, char *name)
  309. {
  310. ACVctl *v;
  311. if(vno < 0 || vno >= 256)
  312. panic("actrapenable: vno %d\n", vno);
  313. v = malloc(sizeof(Vctl));
  314. v->f = f;
  315. v->a = a;
  316. v->vno = vno;
  317. strncpy(v->name, name, KNAMELEN);
  318. v->name[KNAMELEN-1] = 0;
  319. if(acvctl[vno])
  320. panic("AC traps can't be shared");
  321. acvctl[vno] = v;
  322. }