/*****************************************************************
** S T A L L E R . C
** Address Tracing System, Scott Harrington, Spring 94
** Installs Stall Interrupt handler.
** Command line options:
** [-p port] port #(200,220,240,...,3E0) default 300
** [-i IRQ] IRQ #(2,3,6,7) default 7
** [-e [command]] execute command (default COMMAND.COM)
** [-d] debug ISR
** [-m max] stall for a maximum of max loops
** [-r] removes handler for IRQ (default 7)
** If neither -e or -r is used, STALLER stays resident.
*/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#define ISYS_SACK 0x01
#define ISYS_NOTIRQ 0x02
#define ISYS_RUN 0x04
#define ISYS_SRQ 0x08
#define P8259_0 0x20
#define P8259_1 0x21
#define CHECK_LEN 4
#define OCW
#define SPECIFIC_EOI
/* reduce heaplength and stacklength to make a smaller program in memory */
extern unsigned _heaplen = 1024;
extern unsigned _stklen = 512;
void interrupt far stallHandler(void);
void (interrupt far *oldHandler)(void);
void printStatus(void);
unsigned int ioPort = 0x220;
int irq = 7;
int eoi = 0x20; /* non-specific EOI */
char commandPath[80] = "COMMAND";
enum {INSTALL_TSR, REMOVE_TSR, RUN_COMMAND, DEBUG_ISR};
int executionType = INSTALL_TSR;
volatile unsigned char isrVal = 0;
volatile int inISR = 0;
int loopMax = -1;
const int irqHook[] = {-1, -1, 0x0A, 0x0B, -1, -1, 0x0E, 0x0F, -1, 0x70};
const unsigned char enableMask[] = {0xFE, 0xFD, 0xFB, 0xF7,
0xEF, 0xDF, 0xBF, 0x7F, 0xFF};
const unsigned char disableMask[] = {0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80, 0x00};
void main(int argc, char *argv[])
{
int i, ch;
unsigned char mask;
char *parmstr, *endptr;
void far *s1;
void far *s2;
for (i=1; i<argc; i++) {
if (argv[i][0] == '-' && argv[i][1]) {
switch (argv[i][1]) {
case 'p':
parmstr = (argv[i][2]) ? &argv[i][2] : argv[++i];
ioPort = (unsigned int)strtoul(parmstr, &endptr, 0);
break;
case 'i':
parmstr = (argv[i][2]) ? &argv[i][2] : argv[++i];
irq = atoi(parmstr);
break;
case 'e':
parmstr = (argv[i][2]) ? &argv[i][2] : argv[++i];
executionType = RUN_COMMAND;
if (i<=argc && parmstr[0] && parmstr[0] != '-')
strcpy(commandPath, parmstr);
else
i--;
break;
case 'm':
parmstr = (argv[i][2]) ? &argv[i][2] : argv[++i];
loopMax = atoi(parmstr);
break;
case 'd':
executionType = DEBUG_ISR;
break;
case 'r':
executionType = REMOVE_TSR;
break;
case 'h':
default:
printf("Usage: %s [-p port] [-i irq] [-e [cmd]] [-m maxloop] [-r(emove)]\n", argv[0]);
exit(-1);
}
}
else {
printf("Usage: %s [-p port] [-i irq] [-e [cmd]] [-r]\n", argv[0]);
exit(-1);
}
}
if (irqHook[irq] < 0) {
printf("Unsupported IRQ number %d.\n", irq);
exit(-1);
}
#ifdef SPECIFIC_EOI
eoi = 0x60 + (irq&0x07);
#endif
if (ioPort != (ioPort&0x3E0)) {
printf("Valid ports are 0x200, 220, 240, ..., 3E0.\n");
exit(-1);
}
if (executionType == REMOVE_TSR) {
/* Check that previous copy of STALLER is resident, by comparing
the first few bytes of the vector with our handler code. */
s1 = (void far *)stallHandler;
s2 = (void far *)_dos_getvect(irqHook[irq]);
if (_fmemcmp(s1,s2,CHECK_LEN)) {
printf("Previous copy of STALLER not found.\n");
exit(-1);
}
/* Terminate and attempt to release memory of previous handler. */
printStatus();
_disable();
#ifdef OCW
mask = inportb(P8259_1);
outportb(P8259_1, mask | disableMask[irq]);
#endif
_enable();
printStatus();
printf("Removed IRQ %d handler.\n", irq);
printf("I don't know how to release TSR memory.\n");
exit(0);
}
printStatus();
_disable();
oldHandler = _dos_getvect(irqHook[irq]);
_dos_setvect(irqHook[irq], stallHandler);
#ifdef OCW
mask = inportb(P8259_1);
outportb(P8259_1, mask & enableMask[irq]);
#endif
_enable();
printf("Stall Handler hooked to IRQ %d, vector %d, port %x.\n",
irq, irqHook[irq], ioPort);
printf("Old interrupt vector is %Fp.\n", oldHandler);
outportb(ioPort+1, 0); /* Turn recording on */
printStatus();
switch (executionType) {
case INSTALL_TSR:
_dos_keep(0, (_SS + ((_SP+100)/16) - _psp));
/* Does not return...terminates and stays resident. */
case RUN_COMMAND:
system(commandPath);
break;
case DEBUG_ISR:
while (!kbhit())
printStatus();
getch();
break;
}
printStatus();
outportb(ioPort, 0); /* Turn recording off */
_disable();
#ifdef OCW
mask = inportb(P8259_1);
outportb(P8259_1, mask | disableMask[irq]);
#endif
_dos_setvect(irqHook[irq], oldHandler);
_enable();
printf("Stall Handler removed.\n");
printStatus();
}
void printStatus()
{
unsigned char isysReg;
int isysSACK, isysIRQ, isysRUN, isysSRQ;
unsigned char picIMR, picISR, picIRR;
isysReg = inportb(ioPort);
isysSACK = isysReg & ISYS_SACK;
isysIRQ = !(isysReg & ISYS_NOTIRQ);
isysRUN = isysReg & ISYS_RUN;
isysSRQ = isysReg & ISYS_SRQ;
picIMR = inportb(P8259_1);
outportb(P8259_0, 0x0A); /* read register IRR */
picIRR = inportb(P8259_0);
outportb(P8259_0, 0x0B); /* read register ISR */
picISR = inportb(P8259_0);
printf("isrVal=%02X ", isrVal);
printf("isys: %s %s %s %s ",
(isysRUN) ? " RUN " : "stall",
(isysIRQ) ? "IRQ" : "irq",
(isysSRQ) ? "SRQ" : "srq",
(isysSACK) ? "SACK" : "sack");
printf("8259: IMR=%02x ISR=%02x IRR=%02x\n", picIMR, picISR, picIRR);
}
void interrupt far stallHandler()
{
unsigned char mask;
int loopCounter;
#ifdef DEBUGCRAP
if (executionType == DEBUG_ISR) {
isrVal++;
_enable();
/* isrVal = inportb(ioPort);*/
outportb(ioPort,0); /* Turn recording off */
outportb(PIC8259A_0, eoi);
_disable(); /* disable further stalls until we IRET */
}
else {
/* If a stallHandler is already running exit now. */
#endif
if (!inISR) {
#ifdef NOTOURIRQ
if (inportb(ioPort) & ISYS_NOTIRQ)
_chain_intr(oldHandler); /* Not our IRQ! */
else {
#endif
inISR = 1; /* don't _enable until we mark that we're here */
#ifdef OCW_IN_ISR
mask = inportb(P8259_1);
outportb(P8259_1, mask | disableMask[irq]);
#endif
_enable();
isrVal++;
outportb(ioPort,0); /* Turn recording off */
loopCounter = 0;
while (inportb(ioPort) & ISYS_SRQ)
{
if (loopMax != -1 && ++loopCounter >= loopMax)
break;
}
outportb(ioPort+1,0); /* Turn recording on */
/* Send EndOfInterrupt to 8259A PIC */
outportb(P8259_0, eoi);
_disable(); /* disable further stalls until we IRET */
#ifdef OCW_IN_ISR
mask = inportb(P8259_1);
outportb(P8259_1, mask & enableMask[irq]);
#endif
inISR = 0;
/* }*/
}
}