delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2006/02/09/10:53:18

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
Message-ID: <43E8CE28.6090803@mainstreetsoftworks.com>
Date: Tue, 07 Feb 2006 11:43:20 -0500
From: Brad House <brad AT mainstreetsoftworks DOT com>
User-Agent: Mail/News 1.5 (X11/20060131)
MIME-Version: 1.0
To: djgpp AT delorie DOT com
Subject: Re: TSR issues (with code)
References: <43E12016 DOT 2070308 AT mainstreetsoftworks DOT com> <7t88b3-d2q DOT ln1 AT news DOT infowest DOT com> <43E1863D DOT 8080308 AT mainstreetsoftworks DOT com> <fgt8b3-c4u DOT ln1 AT news DOT infowest DOT com> <43E216B4 DOT 70509 AT mainstreetsoftworks DOT com> <43E243F8 DOT 7060401 AT mainstreetsoftworks DOT com> <1o8ab3-2i71 DOT ln1 AT news DOT infowest DOT com> <k2qab3-d7b1 DOT ln1 AT news DOT infowest DOT com> <43E2C6DA DOT 4080700 AT mainstreetsoftworks DOT com> <4mcbb3-q1f1 DOT ln1 AT news DOT infowest DOT com> <43E3884C DOT 8050308 AT mainstreetsoftworks DOT com> <0naeb3-s442 DOT ln1 AT news DOT infowest DOT com> <43E587DC DOT 6080801 AT mainstreetsoftworks DOT com> <js8hb3-7kq2 DOT ln1 AT news DOT infowest DOT com>
In-Reply-To: <js8hb3-7kq2.ln1@news.infowest.com>
Reply-To: djgpp AT delorie DOT com

This is a multi-part message in MIME format.
--------------030907050603050201000902
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

> Good luck.  As soon as you add write() back in, you'll hit the reentrancy
> crash.  Probably some simple logic isn't correct.  Hopefully, it is an easy
> fix, since I think the INDOS/IDLE flags are now correct.  But, if not, there
> is an alternative way to deal with DOS reentrancy.  From DOS 4.0, you can
> save and restore the Swappable Data Area (SDA) using int 0x21, ax=5d06h or
> ax=5d0bh.  The SDA's size is larger if INDOS and smaller if idle.  I have no
> further information on how this works other than Andrew Schulman's
> "Undocumented DOS" has information.  I mention this because you want
> "bullet-proof."  If you find anything on the web on this, other than Ralph
> Brown's Interrupt list info, let me know.

Ok, well, your code definitely worked, but you're right, as soon as you
introduce a write() anywhere, it bombs.  Unfortunately, I need to do a
write (not to the screen, but to disk).  So I've followed every
reference I can find, and I've attached what I've come up with.  It's
a full test suite to turn certain options on and off, and provides
hooks to enable and disable wrapping each bios interrupt individually.

These are the command line arguments for my tsr test program

Usage: rmtsr.exe -dN -n -i[good|all|none|NN] -cNNNN -s -r -h
-dN    debug level N=0-5 (DEFAULT 0)
-iXXXX hook bios interrupts to increment inbios flag for safety
        [all] interrupts
        [good] known good interupts (DEFAULT)
        [none] dont hook bios interrupts
        [NN] interrupt number, may be specified multiple
             times. List: 05 09 0B 0C 0D 0E 10 13 14 16 17
-cNNNN number of calls to make before unloading (DEFAULT 1000)
-ffile location to write output file
-n     do not monitor dosidle interrupt 0x28
-s     clear ss and sp registers before performing a simulate_fcall_iret
        as per the api docs, which will force it to create a small
        temporary stack for the realmode call
-r     restore ss and sp registers after simulate_fcall_iret, only
        relevant if used with -s
-h     help, this menu

I think I'm probably chaining the BIOS interrupts incorrectly
(possibly). From what I've read, I should be able to chain int 13,
and hold when it's active in memory, and just perform a sanity
check before entering the hook on the timer interrupt, if int 13
isn't in the middle of being called, I should be able to simply
disable interrupts, and write to disk.... but... alas ... it
doesn't work :/

Any help would be appreciated.  I think what I've written is actually
a pretty nice test suite, but with no combination of options, can
I get it to work ...  Anytime I specify  -fmyfile.out  it will
lock up hard as a rock... I hope it's something stupid and small,
and not 'impossible'.

I've had the most success with
rmtsr -d1 -c1000 -s -r
but that doesn't ever call 'write()'
(Note that the file appears to be created with the open from
within the tsr, but no data is ever written).

Thanks!
-Brad


--------------030907050603050201000902
Content-Type: text/x-csrc;
 name="testtsr.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="testtsr.c"

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include "tsr.h"

static int cnt = 0;
static int calls_max = 1000;
static int write_file = 0;
static char filename[255];

void tsr_callback(void)
{
	int fd=-1;
	char buf[64];

	cnt++;
	tsr_int2str(buf, (int64_t)cnt);
	if ((cnt % 100) == 0) {
		//tsr_printf("%d of %d\n", cnt, calls_max);
		tsr_write("cnt ", 4);
		tsr_write(buf,strlen(buf));
		tsr_write("\n", 1);
	}
	if (write_file && strlen(filename)) {
		fd = open(filename, O_BINARY|O_WRONLY|O_APPEND|O_CREAT, S_IWUSR);
		if (fd >= 0) {
			//snprintf(text, sizeof(text), "Cnt %d of %d\r\n", cnt, calls_max);
			write(fd, "cnt ", 4);
			write(fd, buf, strlen(buf));
			write(fd, "\r\n", 2);
			close(fd);
		} else {
			//tsr_printf("WARN: could not open '%s' for writing: %s\n", filename, strerror(errno));
		}
	}
	if (cnt == calls_max) {
		tsr_write("removing tsr...\n", 16);
		tsr_remove();
		tsr_write("removed!\n", 9);
	}
}

static void usage(const char *argv0)
{
	printf("Usage: %s -dN -n -i[good|all|none|NN] -cNNNN -s -r -h\r\n"
		   "-dN    debug level N=0-5 (DEFAULT 0)\r\n"
		   "-iXXXX hook bios interrupts to increment inbios flag for safety\r\n"
		   "       [all] interrupts\r\n"
		   "       [good] known good interupts (DEFAULT)\r\n"
		   "       [none] dont hook bios interrupts\r\n"
		   "       [NN] interrupt number, may be specified multiple\r\n"
		   "            times. List: 05 09 0B 0C 0D 0E 10 13 14 16 17\r\n"
		   "-cNNNN number of calls to make before unloading (DEFAULT 1000)\r\n"
		   "-ffile location to write output file\r\n"
		   "-n     do not monitor dosidle interrupt 0x28\r\n"
		   "-s     clear ss and sp registers before performing a simulate_fcall_iret\r\n"
		   "       as per the api docs, which will force it to create a small\r\n"
		   "       temporary stack for the realmode call\r\n"
		   "-r     restore ss and sp registers after simulate_fcall_iret, only\r\n"
		   "       relevant if used with -s\r\n"
		   "-h     help, this menu\r\n",
			argv0);
}

int main(int argc, char **argv)
{
	int i;
	for (i=1; i<argc; i++) {
		if (strncasecmp(argv[i], "-d", 2) == 0) {
			tsr_debuglevel(atoi(argv[i]+2));
		} else if (strncasecmp(argv[i], "-i", 2) == 0) {
			if (strcasecmp(argv[i]+2, "all") == 0) {
				tsr_enableinthook(0, 1);
			} else if (strcasecmp(argv[i]+2, "good") == 0) {
				tsr_enableinthook(0, 2);
			} else {
				tsr_enableinthook(strtol(argv[i]+2,NULL,16), 0);
			}
		} else if (strncasecmp(argv[i], "-c", 2) == 0) {
			calls_max=atoi(argv[i]+2);
		} else if (strncasecmp(argv[i], "-f", 2) == 0) {
			write_file = 1;
			memset(filename, 0, sizeof(filename));
			strncpy(filename, argv[i]+2, sizeof(filename)-1);
			printf("Will write output to '%s'\r\n", filename);
			if (strlen(filename)) unlink(filename);
		} else if (strncasecmp(argv[i], "-n", 2) == 0) {
			tsr_ignoredosidle();
		} else if (strncasecmp(argv[i], "-s", 2) == 0) {
			tsr_clear_ss_sp();
		} else if (strncasecmp(argv[i], "-r", 2) == 0) {
			tsr_restore_ss_sp();
		} else if (strncasecmp(argv[i], "-h", 2) == 0 ||
			       strncasecmp(argv[i], "--help", 6) == 0 ||
				   strncasecmp(argv[i], "-?", 2) == 0 ||
				   strncasecmp(argv[i], "/?", 2) == 0 ||
				   strncasecmp(argv[i], "/h", 2) == 0) {
			usage(argv[0]);
			exit(1);
		} else {
			printf("Unknown option '%s'\r\n", argv[i]);
			usage(argv[0]);
			exit(1);
		}
	}

	printf("Creating tsr...\r\n");
	if (!tsr_create(tsr_callback)) {
		printf("failed\r\n");
		return(1);
	}
	/* Should never actually get here, because
	 * we terminated and stayed resident */
	return(0);
}

--------------030907050603050201000902
Content-Type: text/x-csrc;
 name="tsr.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="tsr.c"

#include <go32.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <io.h>
#include <stdarg.h>
#include <dpmi.h>
#include <sys/farptr.h>
#include <sys/nearptr.h>
#include <crt0.h>
#include <pc.h>
#include <sys/exceptn.h>
#include <dos.h>

#define TIMER_INTERRUPT 0x1c  /* Maybe 0x08 ? */
#define DOSIDLE_INTERRUPT 0x28 /* DOS idle interrupt */

#define asm_cli disable
#define asm_sti enable
#include "tsr.h"

/* FLAG to lock all memory */
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY | _CRT0_FLAG_UNIX_SBRK;

static volatile int indos_offset;    /* saved INDOS flag address */
static volatile int critical_offset; /* saved critical error flag */
static volatile int inbios = 0;      /* similar to indos flag, but generated by
				      * us using interrupt hooks, since DOS is
				      * not reentrant */
static volatile int in_dosidle = 0;  /* check to see if we're in DOSIDLE (int28) */
static volatile int in_callback=0;   /* check to see if it's trying to reenter */

static volatile int64_t in_dosidle_num = 0; /* Number of times dosidle was set */
static volatile int64_t in_bios_num = 0;    /* Number of times bios call was intercepted */
static volatile int64_t in_callback_num = 0; /* Number of times callback was called */
static volatile int64_t in_attempts_num = 0; /* Number of times an attempt was made to
										  * call a callback, though may have been
										  * blocked by indos, criterr, inbios, etc */
static int DEBUG = 0;
static int dont_use_dosidle = 0;	/* ignore dosidle? */
static int clear_ss_sp = 0;	/* Clear ss and sp before simulating fcall iret */
static int restore_ss_sp = 0;

static mycallback int_callback=NULL;

static int nearptr_active = 0;
static int tsr_is_active = 0;

/* Place to store old interrupt vectors */
static _go32_dpmi_seginfo old_timer_seginfo;
static _go32_dpmi_seginfo old_dosidle_seginfo;

/* Register storage */
static _go32_dpmi_registers regs_timer;
static _go32_dpmi_registers regs_dosidle;

/* Place to store new interrupt vector info */
static _go32_dpmi_seginfo timer_seginfo;
static _go32_dpmi_seginfo dosidle_seginfo;

#define INT05 (1<<0)
#define INT09 (1<<1)
#define INT0B (1<<2)
#define INT0C (1<<3)
#define INT0D (1<<4)
#define INT0E (1<<5)
#define INT10 (1<<6)
#define INT13 (1<<7)
#define INT14 (1<<8)
#define INT16 (1<<9)
#define INT17 (1<<10)
#define GOOD_INTS (INT05|INT0B|INT0C|INT0D|INT0E|INT10|INT13|INT14|INT17)
#define ALL_INTS (GOOD_INTS|INT16|INT09)

static int USE_INTERRUPTS = -1; /* Active interrupts */

#define BIOS_VARS(biosint) \
	static _go32_dpmi_seginfo old_bios_seginfo_##biosint; \
	static _go32_dpmi_registers regs_##biosint; \
	static _go32_dpmi_seginfo bios_seginfo_##biosint;
BIOS_VARS(0x05)
BIOS_VARS(0x09)
BIOS_VARS(0x0B)
BIOS_VARS(0x0C)
BIOS_VARS(0x0D)
BIOS_VARS(0x0E)
BIOS_VARS(0x10)
BIOS_VARS(0x13)
BIOS_VARS(0x14)
BIOS_VARS(0x16)
BIOS_VARS(0x17)

static volatile int x=0,y=0;
void tsr_write(const char *str, int len)
{
	char *screen = (char *)0xB8000;
	int i;
	//int ints_were_enabled = 0;

	//ints_were_enabled = asm_cli();
	/* If using nearptrs, we need to make sure calls we
	 * make don't make interrupt calls, otherwise we'd
	 * get a deadlock */
	if (nearptr_active) {
		screen-=__djgpp_base_address;
		for (i=0; i<len; i++) {
			if(str[i]!='\n') {
				screen[x*80*2+2*y]=str[i];
				screen[x*80*2+2*y+1]=0x6F;
				y++;
			}
			if(y==80||str[i]=='\n') {
				y=0;
				x++;
				if(x==25) x=0;
			}
		}
	} else {
		write(1, str, len);
	}
	//if (ints_were_enabled) asm_sti();
}
void tsr_printf(const char *fmt, ...)
{
	char line[255];
	va_list ap;
	va_start(ap,fmt);
	memset(line, 0, sizeof(line));
	vsnprintf(line, sizeof(line), fmt, ap);
	va_end(ap);
	tsr_write(line, strlen(line));
}
static void tsr_debug(int level, const char *fmt, ...)
{
	char line[255];
	va_list ap;
	if (level <= DEBUG) {
		va_start(ap,fmt);
		memset(line, 0, sizeof(line));
		vsnprintf(line, sizeof(line), fmt, ap);
		va_end(ap);
		tsr_write(line, strlen(line));
	}
}

static void tsr_debug_static(int level, const char *str)
{
	if (level <= DEBUG) {
		tsr_write(str, strlen(str));
	}
}

void tsr_debuglevel(int level)
{
	DEBUG=level;
}

/* Calls int 21 ax 0x3100 to tell app to terminate and stay resident */
static void keep(unsigned char status, unsigned size)
{
	_go32_dpmi_registers r;
	tsr_debug_static(2, "keep ");

	memset(&r, 0, sizeof(_go32_dpmi_registers));
	/* Keep size default is current PSP block size */
	if(_farpeekw(_dos_ds,_go32_info_block.linear_address_of_original_psp-15) !=
        	(_go32_info_block.linear_address_of_original_psp/16))
		/* Not a real PSP? attempt to continue */
		r.x.dx=(_go32_info_block.size_of_transfer_buffer+256)/16;
	else
		r.x.dx=_farpeekw(_dos_ds,_go32_info_block.linear_address_of_original_psp-13);


	/* Default is to keep PSP and transfer buffer, but the user may want to */
	/*   not use and release transfer buffer to decrease DOS footprint.  */
	if(size >= 16 && size < r.x.dx)
		r.x.dx=size;

	r.x.ax=0x3100+status;
	__dpmi_int(0x21, &r);
}


static unsigned char _peekb(int dosoffset)
{
	unsigned char c=0;
	tsr_debug_static(5, "_peekb ");
	if (nearptr_active) {
		c=*((char *)dosoffset + __djgpp_conventional_base);
	} else {
		dosmemget(dosoffset, sizeof(c), &c);
	}
	return(c);
}


static int tsr_execute_allowed()
{
	char indos, critical;
	tsr_debug_static(4, "tsr_execute_allowed ");
	if (!tsr_is_active) return(0);

	indos = _peekb(indos_offset);
	critical = _peekb(critical_offset);

	if (indos == 0 && critical == 0 && inbios == 0) return(1);

	/* If we're only in an int28 call, it's ok */
	if (indos == 0x01 && critical == 0 && inbios == 0 && in_dosidle == 1) {
		return(1);
	}
	return(0); 
}

int tsr_int2str(char *buf, int64_t myint)
{
	int place=0,i,c;
	int64_t uvalue = 0;
	uvalue=myint;
	do {
		buf[place++] = ("0123456789")[uvalue % 10];
		uvalue = (uvalue / 10);
	} while (uvalue);
	buf[place]=0;
	/* In reverse order, flip! */
	for (i=0; i<place; i++) {
		if (i>=place-i) break;
		c=buf[i];
		buf[i]=buf[place-i-1];
		buf[place-i-1]=c;
	}
	return(1);
}

#define int2str tsr_int2str

#define BIOS_CALLBACK(biosint) \
		void mybios_callback_##biosint(_go32_dpmi_registers *regs) \
		{ \
			char buf[100]; \
			unsigned short ss, sp; \
			inbios++; \
			in_bios_num++; \
			int2str(buf, (int64_t)biosint); \
			tsr_debug_static(3, "bios_"); \
			tsr_debug_static(3, buf); \
			tsr_debug_static(3, " "); \
			regs->x.cs = old_bios_seginfo_##biosint.rm_segment; \
			regs->x.ip = old_bios_seginfo_##biosint.rm_offset; \
			if (clear_ss_sp) { \
				ss = regs->x.ss; \
				sp = regs->x.sp; \
				regs->x.ss = regs->x.sp = 0; \
			} \
			_go32_dpmi_simulate_fcall_iret(regs); \
			if (clear_ss_sp && restore_ss_sp) { \
				regs->x.ss = ss; \
				regs->x.sp = sp; \
			}\
			tsr_debug_static(3, "bios_end_"); \
			tsr_debug_static(3, buf); \
			tsr_debug_static(3, " "); \
			inbios--; \
		}

BIOS_CALLBACK(0x05);
BIOS_CALLBACK(0x09);
BIOS_CALLBACK(0x0B);
BIOS_CALLBACK(0x0C);
BIOS_CALLBACK(0x0D);
BIOS_CALLBACK(0x0E);
BIOS_CALLBACK(0x10);
BIOS_CALLBACK(0x13);
BIOS_CALLBACK(0x14);
BIOS_CALLBACK(0x16);
BIOS_CALLBACK(0x17);

/* int28 callback */
void mydosidle_function(_go32_dpmi_registers *regs)
{
	unsigned short ss, sp;
	in_dosidle_num++;
	tsr_debug_static(3, "mydosidle_function ");
	/* Increment dosidle cntr so we know we're being */
	/* called from the int28 callback */
	in_dosidle++;

	/* Call original interrupt handler */
	regs->x.cs = old_dosidle_seginfo.rm_segment;
	regs->x.ip = old_dosidle_seginfo.rm_offset;
	if (clear_ss_sp) {
			ss = regs->x.ss;
			sp = regs->x.sp;
			regs->x.ss = regs->x.sp = 0; 
	}
	_go32_dpmi_simulate_fcall_iret(regs);
	if (clear_ss_sp && restore_ss_sp) {
		regs->x.ss = ss;
		regs->x.sp = sp;
	}
	/* Decrement count as we leave the dosidle callback */
	in_dosidle--;
	tsr_debug_static(3, "mydosidle_exit ");
}

void mytimer_function(_go32_dpmi_registers *regs)
{
	int ints_were_enabled;
	unsigned short ss, sp;
	in_attempts_num++;

	tsr_debug_static(2, "mytimer_function ");
	ints_were_enabled=asm_cli(); 

	if (tsr_execute_allowed() && !in_callback) {
		in_callback++;
		in_callback_num++;
		(*int_callback)();
		in_callback--;
	}
	if (ints_were_enabled) asm_sti();

	tsr_debug_static(2, "mytimer_end ");
	/* Only need to chain interrupt if we're using this as
	 * a real-mode callback */
	if (nearptr_active) {
		regs->x.cs = old_timer_seginfo.rm_segment;
		regs->x.ip = old_timer_seginfo.rm_offset;
		if (clear_ss_sp) {
			ss = regs->x.ss;
			sp = regs->x.sp;
			regs->x.ss = regs->x.sp = 0; 
		}
		_go32_dpmi_simulate_fcall_iret(regs);
		if (clear_ss_sp && restore_ss_sp) {
			regs->x.ss = ss;
			regs->x.sp = sp;
		}
	}
}

int tsr_enableinthook(int myint, int flag)
{
	if (flag == 2) {
		USE_INTERRUPTS = GOOD_INTS;
	} else if (flag == 1) {
		USE_INTERRUPTS = ALL_INTS;
	} else if (flag == 0) {
		if (USE_INTERRUPTS == -1)
			USE_INTERRUPTS = 0;
		switch (myint) {
			case 0x05:
				USE_INTERRUPTS|=INT05;
			break;
			case 0x09:
				USE_INTERRUPTS|=INT09;
			break;
			case 0x0B:
				USE_INTERRUPTS|=INT0B;
			break;
			case 0x0C:
				USE_INTERRUPTS|=INT0C;
			break;
			case 0x0D:
				USE_INTERRUPTS|=INT0D;
			break;
			case 0x0E:
				USE_INTERRUPTS|=INT0E;
			break;
			case 0x10:
				USE_INTERRUPTS|=INT10;
			break;
			case 0x13:
				USE_INTERRUPTS|=INT13;
			break;
			case 0x14:
				USE_INTERRUPTS|=INT14;
			break;
			case 0x16:
				USE_INTERRUPTS|=INT16;
			break;
			case 0x17:
				USE_INTERRUPTS|=INT17;
			break;
		}
	} else if (flag == -1) {
		USE_INTERRUPTS = 0;
	} else {
		return(0);
	}
	return(0);
}

int tsr_ignoredosidle()
{
	dont_use_dosidle=1;
	return(1);
}

int tsr_clear_ss_sp()
{
	clear_ss_sp = 1;
	return(1);
}

int tsr_restore_ss_sp()
{
	restore_ss_sp = 1;
	return(1);
}

#define BIOS_HOOK(biosint) \
	tsr_debug(1, "Hook int 0x%x\n", biosint); \
	_go32_dpmi_get_real_mode_interrupt_vector(biosint, &old_bios_seginfo_##biosint); \
	bios_seginfo_##biosint.pm_offset = (unsigned long)&mybios_callback_##biosint; \
	memset(&regs_##biosint, 0, sizeof(_go32_dpmi_registers)); \
	_go32_dpmi_allocate_real_mode_callback_iret(&bios_seginfo_##biosint, &regs_##biosint); \
	_go32_dpmi_set_real_mode_interrupt_vector(biosint, &bios_seginfo_##biosint);

int tsr_create(mycallback hook)
{
	_go32_dpmi_registers r;
	if (!__djgpp_nearptr_enable()) {
		nearptr_active = 0;
		tsr_debug_static(1, "Nearptr support is disabled (XP/2000/NT?)\r\n");
	} else {
		nearptr_active = 1;
		tsr_debug_static(1, "Nearptr support is enabled\r\n");
	}

	/* Locate INDOS flag */
	memset(&r, 0, sizeof(r));
	r.h.ah = 0x34;
	if (__dpmi_int(0x21, &r) == -1 || r.x.flags & 1) {
		tsr_printf("Unable to get indos flag\r\n");
		return(0);
	}
	indos_offset = (r.x.es << 4) | r.x.bx; /* r.x.es * 16 + r.x.bx; */

	/* Locate Critical Error Flag */
	memset(&r, 0, sizeof(r));
	r.x.ax = 0x5D06;
	if (__dpmi_int(0x21, &r) == -1 || r.x.flags & 1) {
		tsr_printf("Unable to get criterr flag\r\n");
		return(0);
	}
	critical_offset = (r.x.ds << 4) | r.x.si; /* r.x.ds * 16 + r.x.si; */

	/* Sanity check, CritErr should be inDos - 1 */
	if (critical_offset != indos_offset-1) {
		tsr_debug(1, "WARN: CritErr should be inDos-1, diff is : %d\r\n", indos_offset-critical_offset);
	}

	tsr_debug(1, "INFO: InDos addr: 0x%x val: 0x%x\r\n"
		"Critical Err addr: 0x%x val: 0x%x\r\n", 
		(int)indos_offset, _peekb(indos_offset),
		(int)critical_offset, _peekb(critical_offset));


	int_callback = hook;

	/* If nearptr is active, that means we can do real mode interrupts, otherwise,
	 * only capture protected mode timer interrupt */
	if (nearptr_active) {
		/* Hook realmode timer interrupt */
		tsr_debug_static(1, "Hooking timer interrupt\n");
		_go32_dpmi_get_real_mode_interrupt_vector(TIMER_INTERRUPT, &old_timer_seginfo);
		timer_seginfo.pm_offset = (unsigned long)&mytimer_function;
		memset(&regs_timer, 0, sizeof(_go32_dpmi_registers));
		_go32_dpmi_allocate_real_mode_callback_iret(&timer_seginfo, &regs_timer);
		_go32_dpmi_set_real_mode_interrupt_vector(TIMER_INTERRUPT, &timer_seginfo);
	
		/* Hook realmode dosidle interrupt */
		if (!dont_use_dosidle) {
			tsr_debug_static(1, "Hooking dosidle interrupt\n");
			_go32_dpmi_get_real_mode_interrupt_vector(DOSIDLE_INTERRUPT, &old_dosidle_seginfo);
			dosidle_seginfo.pm_offset = (unsigned long)&mydosidle_function;
			memset(&regs_dosidle, 0, sizeof(_go32_dpmi_registers));
			_go32_dpmi_allocate_real_mode_callback_iret(&dosidle_seginfo, &regs_dosidle);
			_go32_dpmi_set_real_mode_interrupt_vector(DOSIDLE_INTERRUPT, &dosidle_seginfo);
		}

		if (USE_INTERRUPTS == -1)
			USE_INTERRUPTS = GOOD_INTS;

		/* Hook bios interrupts as suggested by :
		 * Art of Assembly DOS ch 18-3: 
		 * http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH18/CH18-3.html */
		if (USE_INTERRUPTS & INT05)
			BIOS_HOOK(0x05);
		if (USE_INTERRUPTS & INT09)
			BIOS_HOOK(0x09);
		if (USE_INTERRUPTS & INT0B)
			BIOS_HOOK(0x0B);
		if (USE_INTERRUPTS & INT0C)
			BIOS_HOOK(0x0C);
		if (USE_INTERRUPTS & INT0D)
			BIOS_HOOK(0x0D);
		if (USE_INTERRUPTS & INT0E)
			BIOS_HOOK(0x0E);
		if (USE_INTERRUPTS & INT10)
			BIOS_HOOK(0x10);
		if (USE_INTERRUPTS & INT13)
			BIOS_HOOK(0x13);
		if (USE_INTERRUPTS & INT14)
			BIOS_HOOK(0x14);
		if (USE_INTERRUPTS & INT16)
			BIOS_HOOK(0x16);
		if (USE_INTERRUPTS & INT17)
			BIOS_HOOK(0x17);
	} else {
		/* Only need to chain protected mode timer interrupt if under NT/2000/XP */
		tsr_debug_static(1, "XP/NT/2000 hooking ONLY timer interrupt\n");
		if (_go32_dpmi_get_protected_mode_interrupt_vector(TIMER_INTERRUPT, &old_timer_seginfo) != 0) {
			tsr_printf("Unable to get old timer vector\r\n");
			return(0);
		}
		timer_seginfo.pm_selector = _my_cs(); 
		timer_seginfo.pm_offset = (int)mytimer_function;
		_go32_dpmi_chain_protected_mode_interrupt_vector(TIMER_INTERRUPT, &timer_seginfo);
	}

	tsr_debug_static(1, "*******Installing as TSR*******\n");

	__djgpp_exception_toggle();	/* Only needed if exceptions linked */
	tsr_is_active = 1;
	keep(0, 0);			/* Keep Transfer Buffer */
	return(0);
}

#define BIOS_UNHOOK(biosint) \
	int2str(buf, (int64_t)biosint); \
	tsr_debug_static(1, "removing hook on int 0x"); \
	tsr_debug_static(1, buf); \
	tsr_debug_static(1, "\n"); \
	_go32_dpmi_set_real_mode_interrupt_vector(biosint, &old_bios_seginfo_##biosint); \
	_go32_dpmi_free_real_mode_callback(&bios_seginfo_##biosint);

int tsr_remove()
{
	char buf[100];
	/* Restore old vector, people better be removing TSR's in
	 * reverse order (as is standard in DOS behavior!) */
	tsr_debug_static(1, "remove_tsr ");
	if (tsr_is_active) {
		if (nearptr_active) {
			_go32_dpmi_set_real_mode_interrupt_vector(TIMER_INTERRUPT, &old_timer_seginfo);
			_go32_dpmi_free_real_mode_callback(&timer_seginfo);
			if (!dont_use_dosidle) {
    			_go32_dpmi_set_real_mode_interrupt_vector(DOSIDLE_INTERRUPT, &old_dosidle_seginfo);
				_go32_dpmi_free_real_mode_callback(&dosidle_seginfo);
			}

			if (USE_INTERRUPTS & INT05)
				BIOS_UNHOOK(0x05);
			if (USE_INTERRUPTS & INT09)
				BIOS_UNHOOK(0x09);
			if (USE_INTERRUPTS & INT0B)
				BIOS_UNHOOK(0x0B);
			if (USE_INTERRUPTS & INT0C)
				BIOS_UNHOOK(0x0C);
			if (USE_INTERRUPTS & INT0D)
				BIOS_UNHOOK(0x0D);
			if (USE_INTERRUPTS & INT0E)
				BIOS_UNHOOK(0x0E);
			if (USE_INTERRUPTS & INT10)
				BIOS_UNHOOK(0x10);
			if (USE_INTERRUPTS & INT13)
				BIOS_UNHOOK(0x13);
			if (USE_INTERRUPTS & INT14)
				BIOS_UNHOOK(0x14);
			if (USE_INTERRUPTS & INT16)
				BIOS_UNHOOK(0x16);
			if (USE_INTERRUPTS & INT17)
				BIOS_UNHOOK(0x17);
		} else {
			_go32_dpmi_set_protected_mode_interrupt_vector(TIMER_INTERRUPT, &old_timer_seginfo);
		}
		tsr_is_active = 0;
	}
	tsr_debug_static(1, "tsr removed ");
	tsr_debug_static(1, "\n---Stats---\n"
						"in_dosidle_num : ");
	int2str(buf, in_dosidle_num);
	tsr_debug_static(1, buf);
	tsr_debug_static(1, "\nin_bios_num    : ");
	int2str(buf, in_bios_num);
	tsr_debug_static(1, buf);
	tsr_debug_static(1, "\nin_attempts_num: ");
	int2str(buf, in_attempts_num);
	tsr_debug_static(1, buf);
	tsr_debug_static(1, "\nin_callback_num: ");
	int2str(buf, in_callback_num);
	tsr_debug_static(1, buf);
	tsr_debug_static(1, "\n");
	return(1);
}

--------------030907050603050201000902
Content-Type: text/x-chdr;
 name="tsr.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="tsr.h"

#ifndef __TSR_H__
#define __TSR_H__ 1
#ifndef NO_STDINT
#include <stdint.h>
#else
typedef long long int64_t;
#endif
typedef void (*mycallback)(void);
void tsr_debuglevel(int level);
int tsr_create(mycallback hook);
int tsr_remove();
void tsr_write(const char *str, int len);
void tsr_printf(const char *fmt, ...);
int tsr_int2str(char *buf, int64_t myint);
/* If not specified, defaults to hook all known good interrupts,
 * to specify single interrupt, specify myint and set flag as 0
 * to specify all good interrupts, set flag as 2
 * to specify all interrupts, set flag as 1 
 * to disable bios hooks, set flag as -1 */
int tsr_enableinthook(int myint, int flag);
int tsr_ignoredosidle();
int tsr_clear_ss_sp();
int tsr_restore_ss_sp();
#endif

--------------030907050603050201000902--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019