/* -------- resident.c --------- */ #include #include static union REGS rg; static struct SREGS seg; static unsigned mcbseg; static unsigned dosseg; static unsigned dosbusy; static unsigned enddos; char far *intdta; static unsigned intsp; static unsigned intss; static char far *mydta; static unsigned myss; static unsigned stack; static unsigned ctrl_break; static unsigned mypsp; static unsigned intpsp; static unsigned pids[2]; static int pidctr = 0; static int pp; static void interrupt (*oldtimer)(void); static void interrupt (*old28)(void); static void interrupt (*oldkb)(void); static void interrupt (*olddisk)(void); static void interrupt (*oldcrit)(void); extern void interrupt (*ZeroDivVector)(void); static void interrupt newtimer(void); static void interrupt new28(void); static void interrupt newkb(void); static void interrupt newdisk(int,int,int,int,int,int,int,int,int,int,int,int); static void interrupt newcrit(int,int,int,int,int,int,int,int,int,int,int,int); extern unsigned sizeprogram; extern unsigned scancode; extern unsigned keymask; static int resoff = 0; static int running = 0; static int popflg = 0; static int diskflag = 0; static int kbval; static int cflag; static void dores(void); static void pidaddr(void); static void resterm(void); void resident_psp(void); void interrupted_psp(void); void popup(void); /* -------- establish & declare residency --------- */ void resinit() { segread(&seg); myss = seg.ss; /* ------ get address of DOS busy flag ---- */ rg.h.ah = 0x34; intdos(&rg, &rg); dosseg = _ES; dosbusy = rg.x.bx; /* ----- get address of resident program's dta ----- */ mydta = getdta(); /* -------- get addresses of PID in DOS ------- */ pidaddr(); /* ----- get original interrupt vectors ----- */ oldtimer = getvect(0x1c); old28 = getvect(0x28); oldkb = getvect(9); olddisk = getvect(0x13); /* ----- attach vectors to resident program ----- */ setvect(0x1c, newtimer); setvect(9, newkb); setvect(0x28, new28); setvect(0x13, newdisk); /* ------ compute stack pointer ------- */ stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300; /* ---- restore zero divide interrupt vector --- */ setvect(0, ZeroDivVector); /* ----- terminate and stay resident ------- */ rg.x.ax = 0x3100; rg.x.dx = sizeprogram; intdos(&rg, &rg); } /* ------ BIOS disk functions ISR ------- */ static void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs) { diskflag++; (*olddisk)(); ax = _AX; /* for the register returns */ cx = _CX; dx = _DX; newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs); /* to get current flags register */ flgs = cflag; --diskflag; } /* -------- critical error ISR ---------- */ static void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs) { ax = 0; cflag = flgs; /* for newdisk */ } /* ----- keyboard ISR ------ */ static void interrupt newkb() { if (inportb(0x60) == scancode) { kbval = peekb(0, 0x417); if (!resoff && ((kbval & keymask) ^ keymask) == 0) { /* --- reset the keyboard ---- */ kbval = inportb(0x61); outportb(0x61, kbval | 0x80); outportb(0x61, kbval); outportb(0x20, 0x20); /* ---- set hotkey indicator ---- */ if (!running) popflg = 1; return; } } (*oldkb)(); } /* ----- timer ISR ------- */ static void interrupt newtimer() { (*oldtimer)(); if (popflg && peekb(dosseg, dosbusy) == 0) if (diskflag == 0) { outportb(0x20, 0x20); popflg = 0; dores(); } } /* ----- DOSOK ISR -------- */ static void interrupt new28() { (*old28)(); if (popflg && peekb(dosseg, dosbusy) != 0) { popflg = 0; dores(); } } /* ------ switch psp context from interrupted to TSR ----- */ void resident_psp() { /* ------ save interrupted program's psp ----- */ intpsp = peek(dosseg, *pids); /* ----- set resident program's psp ----- */ for (pp = 0; pp < pidctr; pp++) poke(dosseg, pids [pp], mypsp); } /* ---- switch psp context from TSR to interrupted ---- */ void interrupted_psp() { /* ----- reset interrupted program's psp ----- */ for (pp = 0; pp < pidctr; pp++) poke(dosseg, pids [pp], intpsp); } /* ------ execute the resident program ------- */ static void dores() { running = 1; disable(); intsp = _SP; intss = _SS; _SP = stack; _SS = myss; enable(); oldcrit = getvect(0x24);/* redirect critical error */ setvect(0x24, newcrit); rg.x.ax = 0x3300; /* get ctrl break setting */ intdos(&rg, &rg); ctrl_break = rg.h.dl; rg.x.ax = 0x3301; /* turn off ctrl break logic */ rg.h.dl = 0; intdos(&rg, &rg); intdta = getdta(); /* get interrupted dta */ setdta(mydta); /* set resident dta */ resident_psp(); /* swap psps */ popup(); /* execute resident program */ interrupted_psp(); /* reset interrupted psp */ setdta(intdta); /* reset interrupted dta */ setvect(0x24, oldcrit); /* reset critical error */ rg.x.ax = 0x3301; /* reset ctrl break */ rg.h.dl = ctrl_break; intdos(&rg, &rg); disable(); /* reset interrupted stack */ _SP = intsp; _SS = intss; enable(); running = 0; } /*page*/ static int avec = 0; /* ------- test to see if the program is already resident if not, attach to an available interrupt ---------- */ unsigned resident(signature, ifunc) char *signature; void interrupt (*ifunc)(); { char *sg; unsigned df; int vec; segread(&seg); df = seg.ds-seg.cs; for (vec = 0x60; vec < 0x68; vec++) { if (getvect(vec) == NULL) { if (!avec) avec = vec; continue; } for (sg = signature; *sg; sg++) if (*sg!=peekb(peek(0,2+vec*4)+df,(unsigned)sg)) break; if (!*sg) return vec; } if (avec) setvect(avec, ifunc); return 0; } /*page*/ /* -------- find address of PID ---------- */ static void pidaddr() { unsigned adr = 0; /* ------- get the current pid --------- */ rg.h.ah = 0x51; intdos(&rg, &rg); mypsp = rg.x.bx; /* ----- find the end of the DOS segment ------- */ rg.h.ah = 0x52; intdos(&rg, &rg); enddos = _ES; enddos = peek(enddos, rg.x.bx-2); /* ---- search for matches on the pid in dos ---- */ while (pidctr < 2 && (unsigned)((dosseg<<4) + adr) < (enddos<<4)) { if (peek(dosseg, adr) == mypsp) { rg.h.ah = 0x50; rg.x.bx = mypsp + 1; intdos(&rg, &rg); if (peek(dosseg, adr) == mypsp+1) pids[pidctr++] = adr; /* ---- reset the original pid ------ */ rg.h.ah = 0x50; rg.x.bx = mypsp; intdos(&rg, &rg); } adr++; } } /*page*/ /* ------- terminate function ----------- */ static void resterm() { void closefiles(void); closefiles(); /* close TSR files */ /* ----- restore the interrupt vectors ----- */ setvect(0x1c, oldtimer); setvect(9, oldkb); setvect(0x28, old28); setvect(0x13, olddisk); setvect(avec, (void interrupt (*)()) 0); /* ---- get the seg addr of 1st DOS MCB ---- */ rg.h.ah = 0x52; intdos(&rg, &rg); mcbseg = _ES; mcbseg = peek(mcbseg, rg.x.bx-2); /* ---- walk thru mcb chain & release memory ----- */ segread(&seg); while (peekb(mcbseg, 0) == 0x4d) { if (peek(mcbseg, 1) == mypsp) { rg.h.ah = 0x49; seg.es = mcbseg+1; intdosx(&rg, &rg, &seg); } mcbseg += peek(mcbseg, 3) + 1; } } /* --------- terminate the resident program --------- */ void terminate() { if (getvect(0x13) == (void interrupt (*)()) newdisk) if (getvect(9) == newkb) if (getvect(0x28) == new28) if (getvect(0x1c) == newtimer) { resterm(); return; } resoff = 1; /* another TSR is above us, merely suspend */ } /* ------------- restart the resident program --------- */ void restart() { resoff = 0; } /* ------- put the program on hold -------- */ void wait() { resoff = 1; }