acore.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 "amd64.h"
  17. #include "ureg.h"
  18. #include "io.h"
  19. #include "../port/pmc.h"
  20. /*
  21. * NIX code run at the AC.
  22. * This is the "AC kernel".
  23. */
  24. /*
  25. * FPU:
  26. *
  27. * The TC handles the FPU by keeping track of the state for the
  28. * current process. If it has been used and must be saved, it is saved, etc.
  29. * When a process gets to the AC, we handle the FPU directly, and save its
  30. * state before going back to the TC (or the TC state would be stale).
  31. *
  32. * Because of this, each time the process comes back to the AC and
  33. * uses the FPU it will get a device not available trap and
  34. * the state will be restored. This could be optimized because the AC
  35. * is single-process, and we do not have to disable the FPU while
  36. * saving, so it does not have to be restored.
  37. */
  38. extern char* acfpunm(Ureg* ureg, void *unused_voidp);
  39. extern char* acfpumf(Ureg* ureg, void *unused_voidp);
  40. extern char* acfpuxf(Ureg* ureg, void *unused_voidp);
  41. extern void acfpusysprocsetup(Proc*);
  42. extern void _acsysret(void);
  43. extern void _actrapret(void);
  44. ACVctl *acvctl[256];
  45. /*
  46. * Test inter core calls by calling a cores to print something, and then
  47. * waiting for it to complete.
  48. */
  49. static void
  50. testiccfn(void)
  51. {
  52. print("called: %s\n", ( char *)machp()->NIX.icc->data);
  53. }
  54. void
  55. testicc(int i)
  56. {
  57. Mach *mp;
  58. if((mp = sys->machptr[i]) != nil && mp->online != 0){
  59. if(mp->NIX.nixtype != NIXAC){
  60. print("testicc: core %d is not an AC\n", i);
  61. return;
  62. }
  63. print("calling core %d... ", i);
  64. mp->NIX.icc->flushtlb = 0;
  65. snprint(( char *)mp->NIX.icc->data, ICCLNSZ, "<%d>", i);
  66. mfence();
  67. mp->NIX.icc->fn = testiccfn;
  68. mwait(&mp->NIX.icc->fn);
  69. }
  70. }
  71. /*
  72. * Check if the AC kernel (mach) stack has more than 4*KiB free.
  73. * Do not call panic, the stack is gigantic.
  74. */
  75. static void
  76. acstackok(void)
  77. {
  78. char dummy;
  79. char *sstart;
  80. sstart = (char *)machp() - PGSZ - 4*PTSZ - MACHSTKSZ;
  81. if(&dummy < sstart + 4*KiB){
  82. print("ac kernel stack overflow, cpu%d stopped\n", machp()->machno);
  83. DONE();
  84. }
  85. }
  86. /*
  87. * Main scheduling loop done by the application core.
  88. * Some of functions run will not return.
  89. * The system call handler will reset the stack and
  90. * call acsched again.
  91. * We loop because some functions may return and we should
  92. * wait for another call.
  93. */
  94. void
  95. acsched(void)
  96. {
  97. acmmuswitch();
  98. for(;;){
  99. acstackok();
  100. mwait(&machp()->NIX.icc->fn);
  101. if(machp()->NIX.icc->flushtlb)
  102. acmmuswitch();
  103. DBG("acsched: cpu%d: fn %#p\n", machp()->machno, machp()->NIX.icc->fn);
  104. machp()->NIX.icc->fn();
  105. DBG("acsched: cpu%d: idle\n", machp()->machno);
  106. mfence();
  107. machp()->NIX.icc->fn = nil;
  108. }
  109. }
  110. void
  111. acmmuswitch(void)
  112. {
  113. extern Page mach0pml4;
  114. DBG("acmmuswitch mpl4 %#p mach0pml4 %#p m0pml4 %#p\n", machp()->MMU.pml4->pa, mach0pml4.pa, sys->machptr[0]->MMU.pml4->pa);
  115. cr3put(machp()->MMU.pml4->pa);
  116. }
  117. /*
  118. * Beware: up is not set when this function is called.
  119. */
  120. void
  121. actouser(void)
  122. {
  123. #if 0
  124. void xactouser(uint64_t);
  125. Ureg *u;
  126. acfpusysprocsetup(m->proc);
  127. u = m->proc->dbgreg;
  128. DBG("cpu%d: touser usp = %#p entry %#p\n", machp()->machno, u->sp, u->ip);
  129. xactouser(u->sp);
  130. #endif
  131. panic("actouser");
  132. }
  133. void
  134. actrapret(void)
  135. {
  136. /* done by actrap() */
  137. }
  138. /*
  139. * Entered in AP core context, upon traps (system calls go through acsyscall)
  140. * using up->dbgreg means cores MUST be homogeneous.
  141. *
  142. * BUG: We should setup some trapenable() mechanism for the AC,
  143. * so that code like fpu.c could arrange for handlers specific for
  144. * the AC, instead of doint that by hand here.
  145. *
  146. * All interrupts are masked while in the "kernel"
  147. */
  148. void
  149. actrap(Ureg *u)
  150. {
  151. panic("actrap");
  152. #if 0
  153. char *n;
  154. ACVctl *v;
  155. n = nil;
  156. _pmcupdate(m);
  157. if(m->proc != nil){
  158. m->proc->nactrap++;
  159. m->proc->actime1 = fastticks(nil);
  160. }
  161. if(u->type < nelem(acvctl)){
  162. v = acvctl[u->type];
  163. if(v != nil){
  164. DBG("actrap: cpu%d: %ulld\n", machp()->machno, u->type);
  165. n = v->f(u, v->a);
  166. if(n != nil)
  167. goto Post;
  168. return;
  169. }
  170. }
  171. switch(u->type){
  172. case IdtDF:
  173. print("AC: double fault\n");
  174. dumpregs(u);
  175. ndnr();
  176. case IdtIPI:
  177. m->intr++;
  178. DBG("actrap: cpu%d: IPI\n", machp()->machno);
  179. apiceoi(IdtIPI);
  180. break;
  181. case IdtTIMER:
  182. apiceoi(IdtTIMER);
  183. panic("timer interrupt in an AC");
  184. break;
  185. case IdtPF:
  186. /* this case is here for debug only */
  187. m->pfault++;
  188. DBG("actrap: cpu%d: PF cr2 %#ullx\n", machp()->machno, cr2get());
  189. break;
  190. default:
  191. print("actrap: cpu%d: %ulld\n", machp()->machno, u->type);
  192. }
  193. Post:
  194. m->NIX.icc->rc = ICCTRAP;
  195. m->cr2 = cr2get();
  196. memmove(m->proc->dbgreg, u, sizeof *u);
  197. m->NIX.icc->note = n;
  198. fpuprocsave(m->proc);
  199. _pmcupdate(m);
  200. mfence();
  201. m->NIX.icc->fn = nil;
  202. ready(m->proc);
  203. mwait(&m->NIX.icc->fn);
  204. if(m->NIX.icc->flushtlb)
  205. acmmuswitch();
  206. if(m->NIX.icc->fn != actrapret)
  207. acsched();
  208. DBG("actrap: ret\n");
  209. memmove(u, m->proc->dbgreg, sizeof *u);
  210. if(m->proc)
  211. m->proc->actime += fastticks2us(fastticks(nil) - m->proc->actime1);
  212. #endif
  213. }
  214. void
  215. acsyscall(void)
  216. {
  217. panic("acsyscall");
  218. #if 0
  219. Proc *p;
  220. /*
  221. * If we saved the Ureg into m->proc->dbgregs,
  222. * There's nothing else we have to do.
  223. * Otherwise, we should m->proc->dbgregs = u;
  224. */
  225. DBG("acsyscall: cpu%d\n", machp()->machno);
  226. _pmcupdate(m);
  227. p = m->proc;
  228. p->actime1 = fastticks(nil);
  229. m->syscall++; /* would also count it in the TS core */
  230. m->NIX.icc->rc = ICCSYSCALL;
  231. m->cr2 = cr2get();
  232. fpuprocsave(p);
  233. _pmcupdate(m);
  234. mfence();
  235. m->NIX.icc->fn = nil;
  236. ready(p);
  237. /*
  238. * The next call is probably going to make us jmp
  239. * into user code, forgetting all our state in this
  240. * stack, upon the next syscall.
  241. * We don't nest calls in the current stack for too long.
  242. */
  243. acsched();
  244. #endif
  245. }
  246. /*
  247. * Called in AP core context, to return from system call.
  248. */
  249. void
  250. acsysret(void)
  251. {
  252. panic("acsysret");
  253. #if 0
  254. DBG("acsysret\n");
  255. if(m->proc != nil)
  256. m->proc->actime += fastticks2us(fastticks(nil) - m->proc->actime1);
  257. _acsysret();
  258. #endif
  259. }
  260. void
  261. dumpreg(void *u)
  262. {
  263. print("reg is %p\n", u);
  264. ndnr();
  265. }
  266. char *rolename[] =
  267. {
  268. [NIXAC] "AC",
  269. [NIXTC] "TC",
  270. [NIXKC] "KC",
  271. [NIXXC] "XC",
  272. };
  273. void
  274. acmodeset(int mode)
  275. {
  276. switch(mode){
  277. case NIXAC:
  278. case NIXKC:
  279. case NIXTC:
  280. case NIXXC:
  281. break;
  282. default:
  283. panic("acmodeset: bad mode %d", mode);
  284. }
  285. machp()->NIX.nixtype = mode;
  286. }
  287. void
  288. acinit(void)
  289. {
  290. Mach *mp;
  291. Proc *pp;
  292. /*
  293. * Lower the priority of the apic to 0,
  294. * to accept interrupts.
  295. * Raise it later if needed to disable them.
  296. */
  297. apicpri(0);
  298. /*
  299. * Be sure a few assembler assumptions still hold.
  300. * Someone moved m->stack and I had fun debugging...
  301. */
  302. mp = 0;
  303. pp = 0;
  304. assert((uintptr)&mp->proc == 16);
  305. assert((uintptr)&pp->dbgreg == 24);
  306. assert((uintptr)&mp->stack == 24);
  307. }