acore.c 6.8 KB

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