123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include <tos.h>
- #include <pool.h>
- #include "ureg.h"
- #include "io.h"
- #include "../port/pmc.h"
- /*
- * NIX code run at the AC.
- * This is the "AC kernel".
- */
- /*
- * FPU:
- *
- * The TC handles the FPU by keeping track of the state for the
- * current process. If it has been used and must be saved, it is saved, etc.
- * When a process gets to the AC, we handle the FPU directly, and save its
- * state before going back to the TC (or the TC state would be stale).
- *
- * Because of this, each time the process comes back to the AC and
- * uses the FPU it will get a device not available trap and
- * the state will be restored. This could be optimized because the AC
- * is single-process, and we do not have to disable the FPU while
- * saving, so it does not have to be restored.
- */
- extern char* acfpunm(Ureg* ureg, void *unused_voidp);
- extern char* acfpumf(Ureg* ureg, void *unused_voidp);
- extern char* acfpuxf(Ureg* ureg, void *unused_voidp);
- extern void acfpusysprocsetup(Proc*);
- extern void _acsysret(void);
- extern void _actrapret(void);
- ACVctl *acvctl[256];
- /*
- * Test inter core calls by calling a cores to print something, and then
- * waiting for it to complete.
- */
- static void
- testiccfn(void)
- {
- print("called: %s\n", ( char *)machp()->NIX.icc->data);
- }
- void
- testicc(int i)
- {
- Mach *mp;
- if((mp = sys->machptr[i]) != nil && mp->online != 0){
- if(mp->NIX.nixtype != NIXAC){
- print("testicc: core %d is not an AC\n", i);
- return;
- }
- print("calling core %d... ", i);
- mp->NIX.icc->flushtlb = 0;
- snprint(( char *)mp->NIX.icc->data, ICCLNSZ, "<%d>", i);
- mfence();
- mp->NIX.icc->fn = testiccfn;
- mwait(&mp->NIX.icc->fn);
- }
- }
- /*
- * Check if the AC kernel (mach) stack has more than 4*KiB free.
- * Do not call panic, the stack is gigantic.
- */
- static void
- acstackok(void)
- {
- char dummy;
- char *sstart;
- sstart = (char *)machp() - PGSZ - 4*PTSZ - MACHSTKSZ;
- if(&dummy < sstart + 4*KiB){
- print("ac kernel stack overflow, cpu%d stopped\n", machp()->machno);
- DONE();
- }
- }
- /*
- * Main scheduling loop done by the application core.
- * Some of functions run will not return.
- * The system call handler will reset the stack and
- * call acsched again.
- * We loop because some functions may return and we should
- * wait for another call.
- */
- void
- acsched(void)
- {
- acmmuswitch();
- for(;;){
- acstackok();
- mwait(&machp()->NIX.icc->fn);
- if(machp()->NIX.icc->flushtlb)
- acmmuswitch();
- DBG("acsched: cpu%d: fn %#p\n", machp()->machno, machp()->NIX.icc->fn);
- machp()->NIX.icc->fn();
- DBG("acsched: cpu%d: idle\n", machp()->machno);
- mfence();
- machp()->NIX.icc->fn = nil;
- }
- }
- void
- acmmuswitch(void)
- {
- extern Page mach0root;
- DBG("acmmuswitch mpl4 %#p mach0root %#p m0root %#p\n", machp()->MMU.root->pa, mach0root.pa, sys->machptr[0]->MMU.root->pa);
- rootput(machp()->MMU.root->pa);
- }
- /*
- * Beware: up is not set when this function is called.
- */
- void
- actouser(void)
- {
- #if 0
- void xactouser(uint64_t);
- Ureg *u;
- acfpusysprocsetup(m->proc);
- u = m->proc->dbgreg;
- DBG("cpu%d: touser usp = %#p entry %#p\n", machp()->machno, u->sp, u->ip);
- xactouser(u->sp);
- #endif
- panic("actouser");
- }
- void
- actrapret(void)
- {
- /* done by actrap() */
- }
- /*
- * Entered in AP core context, upon traps (system calls go through acsyscall)
- * using up->dbgreg means cores MUST be homogeneous.
- *
- * BUG: We should setup some trapenable() mechanism for the AC,
- * so that code like fpu.c could arrange for handlers specific for
- * the AC, instead of doint that by hand here.
- *
- * All interrupts are masked while in the "kernel"
- */
- void
- actrap(Ureg *u)
- {
- panic("actrap");
- #if 0
- char *n;
- ACVctl *v;
- n = nil;
- _pmcupdate(m);
- if(m->proc != nil){
- m->proc->nactrap++;
- m->proc->actime1 = fastticks(nil);
- }
- if(u->type < nelem(acvctl)){
- v = acvctl[u->type];
- if(v != nil){
- DBG("actrap: cpu%d: %llu\n", machp()->machno, u->type);
- n = v->f(u, v->a);
- if(n != nil)
- goto Post;
- return;
- }
- }
- switch(u->type){
- case IdtDF:
- print("AC: double fault\n");
- dumpregs(u);
- ndnr();
- case IdtIPI:
- m->intr++;
- DBG("actrap: cpu%d: IPI\n", machp()->machno);
- apiceoi(IdtIPI);
- break;
- case IdtTIMER:
- apiceoi(IdtTIMER);
- panic("timer interrupt in an AC");
- break;
- case IdtPF:
- /* this case is here for debug only */
- m->pfault++;
- DBG("actrap: cpu%d: PF cr2 %#llx\n", machp()->machno, cr2get());
- break;
- default:
- print("actrap: cpu%d: %llu\n", machp()->machno, u->type);
- }
- Post:
- m->NIX.icc->rc = ICCTRAP;
- m->cr2 = cr2get();
- memmove(m->proc->dbgreg, u, sizeof *u);
- m->NIX.icc->note = n;
- fpuprocsave(m->proc);
- _pmcupdate(m);
- mfence();
- m->NIX.icc->fn = nil;
- ready(m->proc);
- mwait(&m->NIX.icc->fn);
- if(m->NIX.icc->flushtlb)
- acmmuswitch();
- if(m->NIX.icc->fn != actrapret)
- acsched();
- DBG("actrap: ret\n");
- memmove(u, m->proc->dbgreg, sizeof *u);
- if(m->proc)
- m->proc->actime += fastticks2us(fastticks(nil) - m->proc->actime1);
- #endif
- }
- void
- acsyscall(void)
- {
- panic("acsyscall");
- #if 0
- Proc *p;
- /*
- * If we saved the Ureg into m->proc->dbgregs,
- * There's nothing else we have to do.
- * Otherwise, we should m->proc->dbgregs = u;
- */
- DBG("acsyscall: cpu%d\n", machp()->machno);
- _pmcupdate(m);
- p = m->proc;
- p->actime1 = fastticks(nil);
- m->syscall++; /* would also count it in the TS core */
- m->NIX.icc->rc = ICCSYSCALL;
- m->cr2 = cr2get();
- fpuprocsave(p);
- _pmcupdate(m);
- mfence();
- m->NIX.icc->fn = nil;
- ready(p);
- /*
- * The next call is probably going to make us jmp
- * into user code, forgetting all our state in this
- * stack, upon the next syscall.
- * We don't nest calls in the current stack for too long.
- */
- acsched();
- #endif
- }
- /*
- * Called in AP core context, to return from system call.
- */
- void
- acsysret(void)
- {
- panic("acsysret");
- #if 0
- DBG("acsysret\n");
- if(m->proc != nil)
- m->proc->actime += fastticks2us(fastticks(nil) - m->proc->actime1);
- _acsysret();
- #endif
- }
- void
- dumpreg(void *u)
- {
- print("reg is %p\n", u);
- ndnr();
- }
- char *rolename[] =
- {
- [NIXAC] = "AC",
- [NIXTC] = "TC",
- [NIXKC] = "KC",
- [NIXXC] = "XC",
- };
- void
- acmodeset(int mode)
- {
- switch(mode){
- case NIXAC:
- case NIXKC:
- case NIXTC:
- case NIXXC:
- break;
- default:
- panic("acmodeset: bad mode %d", mode);
- }
- machp()->NIX.nixtype = mode;
- }
- void
- acinit(void)
- {
- Mach *mp;
- Proc *pp;
- /*
- * Lower the priority of the apic to 0,
- * to accept interrupts.
- * Raise it later if needed to disable them.
- */
- panic("apicpri");
- //apicpri(0);
- /*
- * Be sure a few assembler assumptions still hold.
- * Someone moved m->stack and I had fun debugging...
- */
- mp = 0;
- pp = 0;
- assert((uintptr)&mp->proc == 16);
- assert((uintptr)&pp->dbgreg == 24);
- assert((uintptr)&mp->stack == 24);
- }
|