/*********************************P2TEST.C******************************* * * Test program for the Kaya Kernel: phase 2. * * Produces progress messages on Terminal0. * * This is pretty convoluted code, so good luck! * * Aborts as soon as an error is detected. * * * Modified by Michael Goldweber on June 19, 2020 */ #include "../h/pandos_const.h" #include "../h/pandos_types.h" #include extern void bp(); typedef unsigned int devregtr; /* hardware constants */ #define PRINTCHR 2 #define BYTELEN 8 #define RECVD 5 #define CLOCKINTERVAL 100000UL /* interval to V clock semaphore */ #define TERMSTATMASK 0xFF #define CAUSEMASK 0xFF #define VMOFF 0xF8FFFFFF #define SYSCAUSE (0x8 << 2) #define BUSERROR 6 #define RESVINSTR 10 #define ADDRERROR 4 #define SYSCALLEXCPT 8 #define QPAGE 1024 #define IEPBITON 0x4 #define KUPBITON 0x8 #define KUPBITOFF 0xFFFFFFF7 #define TEBITON 0x08000000 #define CAUSEINTMASK 0xFD00 #define CAUSEINTOFFS 10 #define MINLOOPTIME 30000 #define LOOPNUM 10000 #define CLOCKLOOP 10 #define MINCLOCKLOOP 3000 #define BADADDR 0xFFFFFFFF #define TERM0ADDR 0x10000254 /* system call codes */ #define CREATETHREAD 1 /* create thread */ #define TERMINATETHREAD 2 /* terminate thread */ #define PASSERN 3 /* P a semaphore */ #define VERHOGEN 4 /* V a semaphore */ #define WAITIO 5 /* delay on a io semaphore */ #define GETCPUTIME 6 /* get cpu time used to date */ #define WAITCLOCK 7 /* delay on the clock semaphore */ #define GETSPTPTR 8 /* return support structure ptr. */ #define CREATENOGOOD -1 /* just to be clear */ #define SEMAPHORE int #define NOLEAVES 4 /* number of leaves of p8 process tree */ #define MAXSEM 20 int volte = 0; SEMAPHORE term_mut=1, /* for mutual exclusion on terminal */ s[MAXSEM+1], /* semaphore array */ testsem=0, /* for a simple test */ startp2=0, /* used to start p2 */ endp2=0, /* used to signal p2's demise */ endp3=0, /* used to signal p3's demise */ blkp4=1, /* used to block second incaration of p4 */ synp4=0, /* used to allow p4 incarnations to synhronize */ endp4=0, /* to signal demise of p4 */ endp5=0, /* to signal demise of p5 */ endp8=0, /* to signal demise of p8 */ endcreate=0, /* for a p8 leaf to signal its creation */ blkp8=0; /* to block p8 */ state_t p2state, p3state, p4state, p5state, p6state, p7state,p8rootstate, child1state, child2state, gchild1state, gchild2state, gchild3state, gchild4state; /* support structure for p5 */ support_t pFiveSupport; int p1p2synch=0; /* to check on p1/p2 synchronization */ int p8inc; /* p8's incarnation number */ int p4inc=1; /* p4 incarnation number */ unsigned int p5Stack; /* so we can allocate new stack for 2nd p5 */ int creation = 0; /* return code for SYSCALL invocation */ memaddr *p5MemLocation = 0; /* To cause a p5 trap */ void p2(),p3(),p4(),p5(),p5a(),p5b(),p6(),p7(),p7a(),p5prog(),p5mm(); void p5sys(),p8root(),child1(),child2(),p8leaf(); extern void p5gen (); extern void p5mm (); /* a procedure to print on terminal 0 */ void print(char *msg) { char *s = msg; devregtr * base = (devregtr *) (TERM0ADDR); devregtr status; SYSCALL(PASSERN, (int)&term_mut, 0, 0); /* P(term_mut) */ while (*s != EOS) { *(base + 3) = PRINTCHR | (((devregtr) *s) << BYTELEN); status = SYSCALL(WAITIO, TERMINT, 0, 0); if ((status & TERMSTATMASK) != RECVD) { PANIC(); } s++; } SYSCALL(VERHOGEN, (int)&term_mut, 0, 0); /* V(term_mut) */ } /* TLB-Refill Handler */ /* One can place debug calls here, but not calls to print */ void uTLB_RefillHandler () { setENTRYHI(0x80000000); setENTRYLO(0x00000000); TLBWR(); LDST ((state_t *) 0x0FFFF000); } /*********************************************************************/ /* */ /* p1 -- the root process */ /* */ void test() { bp(); // testing purpose print("PHASE 2\n"); SYSCALL(VERHOGEN, (int)&testsem, 0, 0); /* V(testsem) */ print("p1 v(testsem)\n"); /* set up states of the other processes */ /* set up p2's state */ STST(&p2state); /* create a state area */ p2state.reg_sp = p2state.reg_sp - QPAGE; /* stack of p2 should sit above */ p2state.pc_epc = p2state.reg_t9 = (memaddr)p2; /* p2 starts executing function p2 */ p2state.status = p2state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p3state); p3state.reg_sp = p2state.reg_sp - QPAGE; p3state.pc_epc = p3state.reg_t9 = (memaddr)p3; p3state.status = p3state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p4state); p4state.reg_sp = p3state.reg_sp - QPAGE; p4state.pc_epc = p4state.reg_t9 = (memaddr)p4; p4state.status = p4state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p5state); p5Stack = p5state.reg_sp = p4state.reg_sp - (2 * QPAGE); /* because there will 2 p4 running*/ p5state.pc_epc = p5state.reg_t9 = (memaddr)p5; p5state.status = p5state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p6state); p6state.reg_sp = p5state.reg_sp - (2 * QPAGE); p6state.pc_epc = p6state.reg_t9 = (memaddr)p6; p6state.status = p6state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p7state); p7state.reg_sp = p6state.reg_sp - QPAGE; p7state.pc_epc = p7state.reg_t9 = (memaddr)p7; p7state.status = p7state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&p8rootstate); p8rootstate.reg_sp = p7state.reg_sp - QPAGE; p8rootstate.pc_epc = p8rootstate.reg_t9 = (memaddr)p8root; p8rootstate.status = p8rootstate.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&child1state); child1state.reg_sp = p8rootstate.reg_sp - QPAGE; child1state.pc_epc = child1state.reg_t9 = (memaddr)child1; child1state.status = child1state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&child2state); child2state.reg_sp = child1state.reg_sp - QPAGE; child2state.pc_epc = child2state.reg_t9 = (memaddr)child2; child2state.status = child2state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&gchild1state); gchild1state.reg_sp = child2state.reg_sp - QPAGE; gchild1state.pc_epc = gchild1state.reg_t9 = (memaddr)p8leaf; gchild1state.status = gchild1state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&gchild2state); gchild2state.reg_sp = gchild1state.reg_sp - QPAGE; gchild2state.pc_epc = gchild2state.reg_t9 = (memaddr)p8leaf; gchild2state.status = gchild2state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&gchild3state); gchild3state.reg_sp = gchild2state.reg_sp - QPAGE; gchild3state.pc_epc = gchild3state.reg_t9 = (memaddr)p8leaf; gchild3state.status = gchild3state.status | IEPBITON | CAUSEINTMASK | TEBITON; STST(&gchild4state); gchild4state.reg_sp = gchild3state.reg_sp - QPAGE; gchild4state.pc_epc = gchild4state.reg_t9 = (memaddr)p8leaf; gchild4state.status = gchild4state.status | IEPBITON | CAUSEINTMASK | TEBITON; /* create process p2 */ SYSCALL(CREATETHREAD, (int)&p2state, (int) NULL , 0); /* start p2 */ bp(); //testing purpose print("p2 was started\n"); SYSCALL(VERHOGEN, (int)&startp2, 0, 0); /* V(startp2) */ SYSCALL(PASSERN, (int)&endp2, 0, 0); /* P(endp2) */ bp(); // testing purpose /* make sure we really blocked */ if (p1p2synch == 0) print("error: p1/p2 synchronization bad\n"); SYSCALL(CREATETHREAD, (int)&p3state, (int) NULL, 0); /* start p3 */ bp(); // testing purposes print("p3 is started\n"); SYSCALL(PASSERN, (int)&endp3, 0, 0); /* P(endp3) */ SYSCALL(CREATETHREAD, (int)&p4state, (int) NULL, 0); /* start p4 */ pFiveSupport.sup_exceptContext[GENERALEXCEPT].stackPtr = (int) p5Stack; pFiveSupport.sup_exceptContext[GENERALEXCEPT].status = ALLOFF | IEPBITON | CAUSEINTMASK | TEBITON; pFiveSupport.sup_exceptContext[GENERALEXCEPT].pc = (memaddr) p5gen; pFiveSupport.sup_exceptContext[PGFAULTEXCEPT].stackPtr = p5Stack; pFiveSupport.sup_exceptContext[PGFAULTEXCEPT].status = ALLOFF | IEPBITON | CAUSEINTMASK | TEBITON; pFiveSupport.sup_exceptContext[PGFAULTEXCEPT].pc = (memaddr) p5mm; SYSCALL(CREATETHREAD, (int)&p5state, (int) &(pFiveSupport), 0); /* start p5 */ SYSCALL(CREATETHREAD, (int)&p6state, (int) NULL, 0); /* start p6 */ SYSCALL(CREATETHREAD, (int)&p7state, (int) NULL, 0); /* start p7 */ SYSCALL(PASSERN, (int)&endp5, 0, 0); /* P(endp5) */ print("p1 knows p5 ended\n"); SYSCALL(PASSERN, (int)&blkp4, 0, 0); /* P(blkp4) */ /* now for a more rigorous check of process termination */ for (p8inc=0; p8inc<4; p8inc++) { creation = SYSCALL(CREATETHREAD, (int)&p8rootstate, (int) NULL, 0); if (creation == CREATENOGOOD) { print("error in process termination\n"); PANIC(); } SYSCALL(PASSERN, (int)&endp8, 0, 0); } print("p1 finishes OK -- TTFN\n"); * ((memaddr *) BADADDR) = 0; /* terminate p1 */ /* should not reach this point, since p1 just got a program trap */ print("error: p1 still alive after progtrap & no trap vector\n"); PANIC(); /* PANIC !!! */ } /* p2 -- semaphore and cputime-SYS test process */ void p2() { int i; /* just to waste time */ cpu_t now1,now2; /* times of day */ cpu_t cpu_t1,cpu_t2; /* cpu time used */ SYSCALL(PASSERN, (int)&startp2, 0, 0); /* P(startp2) */ print("p2 starts\n"); /* initialize all semaphores in the s[] array */ for (i=0; i<= MAXSEM; i++) s[i] = 0; /* V, then P, all of the semaphores in the s[] array */ for (i=0; i<= MAXSEM; i++) { SYSCALL(VERHOGEN, (int)&s[i], 0, 0); /* V(S[I]) */ SYSCALL(PASSERN, (int)&s[i], 0, 0); /* P(S[I]) */ if (s[i] != 0) print("error: p2 bad v/p pairs\n"); } print("p2 v's successfully\n"); /* test of SYS6 */ STCK(now1); /* time of day */ cpu_t1 = SYSCALL(GETCPUTIME, 0, 0, 0); /* CPU time used */ /* delay for several milliseconds */ for (i=1; i < LOOPNUM; i++) ; cpu_t2 = SYSCALL(GETCPUTIME, 0, 0, 0); /* CPU time used */ STCK(now2); /* time of day */ if (((now2 - now1) >= (cpu_t2 - cpu_t1)) && ((cpu_t2 - cpu_t1) >= (MINLOOPTIME / (* ((cpu_t *)TIMESCALEADDR))))) print("p2 is OK\n"); else { if ((now2 - now1) < (cpu_t2 - cpu_t1)) print ("error: more cpu time than real time\n"); if ((cpu_t2 - cpu_t1) < (MINLOOPTIME / (* ((cpu_t *)TIMESCALEADDR)))) print ("error: not enough cpu time went by\n"); print("p2 blew it!\n"); } p1p2synch = 1; /* p1 will check this */ SYSCALL(VERHOGEN, (int)&endp2, 0, 0); /* V(endp2) */ SYSCALL(TERMINATETHREAD, 0, 0, 0); /* terminate p2 */ /* just did a SYS2, so should not get to this point */ print("error: p2 didn't terminate\n"); PANIC(); /* PANIC! */ } /* p3 -- clock semaphore test process */ void p3() { cpu_t time1, time2; cpu_t cpu_t1,cpu_t2; /* cpu time used */ int i; time1 = 0; time2 = 0; /* loop until we are delayed at least half of clock V interval */ while (time2-time1 < (CLOCKINTERVAL >> 1) ) { STCK(time1); /* time of day */ SYSCALL(WAITCLOCK, 0, 0, 0); STCK(time2); /* new time of day */ } print("p3 - WAITCLOCK OK\n"); /* now let's check to see if we're really charge for CPU time correctly */ cpu_t1 = SYSCALL(GETCPUTIME, 0, 0, 0); for (i=0; i> 2; switch (exeCode) { case BUSERROR: print("Bus Error: Access non-existent memory \n"); pFiveSupport.sup_exceptState[GENERALEXCEPT].pc_epc = (memaddr)p5a; /* Continue with p5a() */ pFiveSupport.sup_exceptState[GENERALEXCEPT].reg_t9 = (memaddr)p5a; /* Continue with p5a() */ break; case RESVINSTR: print("privileged instruction\n"); /* return in kernel mode */ pFiveSupport.sup_exceptState[GENERALEXCEPT].pc_epc = (memaddr)p5b; /* Continue with p5b() */ pFiveSupport.sup_exceptState[GENERALEXCEPT].reg_t9 = (memaddr)p5b; /* Continue with p5b() */ pFiveSupport.sup_exceptState[GENERALEXCEPT].status = pFiveSupport.sup_exceptState[GENERALEXCEPT].status & KUPBITOFF; break; case ADDRERROR: print("Address Error: non-kuseg access w/KU=1\n"); /* return in kernel mode */ pFiveSupport.sup_exceptState[GENERALEXCEPT].pc_epc = (memaddr)p5b; /* Continue with p5b() */ pFiveSupport.sup_exceptState[GENERALEXCEPT].reg_t9 = (memaddr)p5b; /* Continue with p5b() */ pFiveSupport.sup_exceptState[GENERALEXCEPT].status = pFiveSupport.sup_exceptState[GENERALEXCEPT].status & KUPBITOFF; break; case SYSCALLEXCPT: p5sys(); break; default: print("other program trap\n"); } LDST(&(pFiveSupport.sup_exceptState[GENERALEXCEPT])); } /* p5's memory management trap handler */ void p5mm() { print("memory management trap\n"); support_t* pFiveSupAddr = (support_t *)SYSCALL(GETSPTPTR, 0, 0, 0); if ((pFiveSupAddr) != &(pFiveSupport)) { print("Support Structure Address Error\n"); } else{ print("Correct Support Structure Address\n"); } pFiveSupport.sup_exceptState[PGFAULTEXCEPT].status = pFiveSupport.sup_exceptState[PGFAULTEXCEPT].status | KUPBITON; /* user mode on */ pFiveSupport.sup_exceptState[PGFAULTEXCEPT].pc_epc = (memaddr)p5b; /* return to p5b() */ pFiveSupport.sup_exceptState[PGFAULTEXCEPT].reg_t9 = (memaddr)p5b; /* return to p5b() */ LDST(&(pFiveSupport.sup_exceptState[PGFAULTEXCEPT])); } /* p5's SYS trap handler */ void p5sys() { unsigned int p5status = pFiveSupport.sup_exceptState[GENERALEXCEPT].status; p5status = (p5status << 28) >> 31; switch(p5status) { case ON: print("High level SYS call from user mode process\n"); break; case OFF: print("High level SYS call from kernel mode process\n"); break; } pFiveSupport.sup_exceptState[GENERALEXCEPT].pc_epc = pFiveSupport.sup_exceptState[GENERALEXCEPT].pc_epc + 4; /* to avoid SYS looping */ LDST(&(pFiveSupport.sup_exceptState[GENERALEXCEPT])); } /* p5 -- SYS5 test process */ void p5() { print("p5 starts\n"); /* cause a pgm trap access some non-existent memory */ *p5MemLocation = *p5MemLocation + 1; /* Should cause a program trap */ } void p5a() { /* generage a TLB exception after a TLB-Refill event */ p5MemLocation = (memaddr *) 0x80000000; *p5MemLocation = 42; } /* second part of p5 - should be entered in user mode first time through */ /* should generate a program trap (Address error) */ void p5b() { cpu_t time1, time2; SYSCALL(9, 0, 0, 0); SYSCALL(PASSERN, (int)&endp4, 0, 0); /* P(endp4)*/ /* do some delay to be reasonably sure p4 and its offspring are dead */ time1 = 0; time2 = 0; while (time2 - time1 < (CLOCKINTERVAL >> 1)) { STCK(time1); SYSCALL(WAITCLOCK, 0, 0, 0); STCK(time2); } /* if p4 and offspring are really dead, this will increment blkp4 */ SYSCALL(VERHOGEN, (int)&blkp4, 0, 0); /* V(blkp4) */ SYSCALL(VERHOGEN, (int)&endp5, 0, 0); /* V(endp5) */ /* should cause a termination */ /* since this has already been */ /* done for PROGTRAPs */ /* SYSCALL(SPECTRAPVEC, PROGTRAP, (int)&pstat_o, (int)&pstat_n); */ SYSCALL(TERMINATETHREAD, 0, 0, 0); /* should have terminated, so should not get to this point */ print("error: p5 didn't terminate\n"); PANIC(); /* PANIC */ } /*p6 -- high level syscall without initializing passup vector */ void p6() { print("p6 starts\n"); SYSCALL(9, 0, 0, 0); /* should cause termination because p6 has no trap vector */ print("error: p6 alive after SYS9() with no trap vector\n"); PANIC(); } /*p7 -- program trap without initializing passup vector */ void p7() { print("p7 starts\n"); * ((memaddr *) BADADDR) = 0; print("error: p7 alive after program trap with no trap vector\n"); PANIC(); } /* p8root -- test of termination of subtree of processes */ /* create a subtree of processes, wait for the leaves to block, signal*/ /* the root process, and then terminate */ void p8root() { int grandchild; print("p8root starts\n"); SYSCALL(CREATETHREAD, (int)&child1state, (int) NULL, 0); SYSCALL(CREATETHREAD, (int)&child2state, (int) NULL, 0); for (grandchild=0; grandchild < NOLEAVES; grandchild++) { SYSCALL(PASSERN, (int)&endcreate, 0, 0); } SYSCALL(VERHOGEN, (int)&endp8, 0, 0); SYSCALL(TERMINATETHREAD, 0, 0, 0); } /*child1 & child2 -- create two sub-processes each*/ void child1() { print("child1 starts\n"); SYSCALL(CREATETHREAD, (int)&gchild1state, (int) NULL, 0); SYSCALL(CREATETHREAD, (int)&gchild2state, (int) NULL, 0); SYSCALL(PASSERN, (int)&blkp8, 0, 0); } void child2() { print("child2 starts\n"); SYSCALL(CREATETHREAD, (int)&gchild3state, (int) NULL, 0); SYSCALL(CREATETHREAD, (int)&gchild4state, (int) NULL, 0); SYSCALL(PASSERN, (int)&blkp8, 0, 0); } /*p8leaf -- code for leaf processes*/ void p8leaf() { print("leaf process starts\n"); SYSCALL(VERHOGEN, (int)&endcreate, 0, 0); SYSCALL(PASSERN, (int)&blkp8, 0, 0); }