/* Machine or compiler-dependent portions of kernel * Turbo-C version for PC * * Copyright 1991 Phil Karn, KA9Q */ #include #include #include "global.h" #include "proc.h" #include "pc.h" #include "commands.h" static char *Taskers[] = { "", "DoubleDos", "DesqView", "Windows", }; static oldNull; /* Template for contents of jmp_buf in Turbo C */ struct env { unsigned sp; unsigned ss; unsigned flag; unsigned cs; unsigned ip; unsigned bp; unsigned di; unsigned es; unsigned si; unsigned ds; }; static int chkintstk __ARGS((void)); static int stkutil __ARGS((struct proc *pp)); void kinit() { int i; /* Initialize interrupt stack for high-water-mark checking */ for(i=0;i<512;i++) Intstk[i] = STACKPAT; /* Remember location 0 pattern to detect null pointer derefs */ oldNull = *(unsigned short *)NULL; } /* Print process table info * Since things can change while ps is running, the ready proceses are * displayed last. This is because an interrupt can make a process ready, * but a ready process won't spontaneously become unready. Therefore a * process that changes during ps may show up twice, but this is better * than not having it showing up at all. */ int ps(argc,argv,p) int argc; char *argv[]; void *p; { register struct proc *pp; register struct env *ep; int i; tprintf("Uptime %s Stack %x max intstk %u psp %x",tformat(secclock()), getss(),chkintstk(),_psp); if(Mtasker != 0){ tprintf(" Running under %s",Taskers[Mtasker]); } tprintf("\n"); tprintf("PID SP stksize maxstk event fl in out name\n"); for(pp = Susptab;pp != NULLPROC;pp = pp->next){ ep = (struct env *)&pp->env; if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %3d %3d %s\n", ptol(pp), ptol(MK_FP(ep->ss,ep->sp)), pp->stksize, stkutil(pp), ptol(pp->event), pp->i_state ? 'I' : ' ', (pp->state & WAITING) ? 'W' : ' ', (pp->state & SUSPEND) ? 'S' : ' ', pp->input, pp->output, pp->name) == EOF) return 0; } for(i=0;inext){ ep = (struct env *)&pp->env; if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %2d %2d %s\n", ptol(pp),ptol(MK_FP(ep->ss,ep->sp)),pp->stksize,stkutil(pp), ptol(pp->event), pp->i_state ? 'I' : ' ', (pp->state & WAITING) ? 'W' : ' ', (pp->state & SUSPEND) ? 'S' : ' ', pp->input,pp->output, pp->name) == EOF) return 0; } } for(pp = Rdytab;pp != NULLPROC;pp = pp->next){ ep = (struct env *)&pp->env; if(tprintf("%-10lx%-10lx%-10u%-10u %c%c%c %2d %2d %s\n", ptol(pp),ptol(MK_FP(ep->ss,ep->sp)),pp->stksize,stkutil(pp), pp->i_state ? 'I' : ' ', (pp->state & WAITING) ? 'W' : ' ', (pp->state & SUSPEND) ? 'S' : ' ', pp->input,pp->output, pp->name) == EOF) return 0; } if(Curproc != NULLPROC){ ep = (struct env *)&Curproc->env; tprintf("%-10lx%-10lx%-10u%-10u %c %2d %2d %s\n", ptol(Curproc),ptol(MK_FP(ep->ss,ep->sp)),Curproc->stksize, stkutil(Curproc), Curproc->i_state ? 'I' : ' ', Curproc->input,Curproc->output, Curproc->name); } return 0; } static int stkutil(pp) struct proc *pp; { unsigned i; register int16 *sp; i = pp->stksize; for(sp = pp->stack;*sp == STACKPAT && sp < pp->stack + pp->stksize;sp++) i--; return i; } /* Return number of used words in interrupt stack. Note hardwired value * for stack size; this is also found in the various .asm files */ static int chkintstk() { register int i; register int16 *cp; for(i=512,cp = Intstk; i != 0 && *cp == STACKPAT; cp++) i--; return i; } /* Verify that stack pointer for current process is within legal limits; * also check that no one has dereferenced a null pointer */ void chkstk() { int16 *sbase; int16 *stop; int16 *sp; sp = MK_FP(_SS,_SP); if(_SS == _DS){ /* Probably in interrupt context */ return; } sbase = Curproc->stack; if(sbase == NULL) return; /* Main task -- too hard to check */ stop = sbase + Curproc->stksize; if(sp < sbase || sp >= stop){ printf("Stack violation, process %s\n",Curproc->name); printf("SP = %lx, legal stack range [%lx,%lx)\n", ptol(sp),ptol(sbase),ptol(stop)); fflush(stdout); killself(); } if(*(unsigned short *)NULL != oldNull){ printf("WARNING: Location 0 smashed, process %s\n",Curproc->name); *(unsigned short *)NULL = oldNull; fflush(stdout); } } /* Machine-dependent initialization of a task */ void psetup(pp,iarg,parg1,parg2,pc) struct proc *pp; /* Pointer to task structure */ int iarg; /* Generic integer arg */ void *parg1; /* Generic pointer arg #1 */ void *parg2; /* Generic pointer arg #2 */ void (*pc)(); /* Initial execution address */ { register int *stktop; register struct env *ep; /* Set up stack to make it appear as if the user's function was called * by killself() with the specified arguments. When the user returns, * killself() automatically cleans up. * * First, push args on stack in reverse order, simulating what C * does just before it calls a function. */ stktop = (int *)(pp->stack + pp->stksize); #ifdef LARGEDATA *--stktop = FP_SEG(parg2); #endif *--stktop = FP_OFF(parg2); #ifdef LARGEDATA *--stktop = FP_SEG(parg1); #endif *--stktop = FP_OFF(parg1); *--stktop = iarg; /* Now push the entry address of killself(), simulating the call to * the user function. */ #ifdef LARGECODE *--stktop = FP_SEG(killself); #endif *--stktop = FP_OFF(killself); /* Set up task environment. Note that for Turbo-C, the setjmp * sets the interrupt enable flag in the environment so that * interrupts will be enabled when the task runs for the first time. * Note that this requires newproc() to be called with interrupts * enabled! */ setjmp(pp->env); ep = (struct env *)&pp->env; ep->ss = FP_SEG(stktop); ep->sp = FP_OFF(stktop); ep->cs = FP_SEG(pc); /* Doesn't hurt in small model */ ep->ip = FP_OFF(pc); ep->bp = 0; /* Anchor stack traces */ /* Task initially runs with interrupts on */ pp->i_state = 1; } unsigned phash(event) void *event; { register unsigned x; /* Fold the two halves of the pointer */ x = FP_SEG(event) ^ FP_OFF(event); /* If PHASH is a power of two, this will simply mask off the * higher order bits */ return x % PHASH; }