delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2006/02/01/16:16:49

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
Message-ID: <43E12016.2070308@mainstreetsoftworks.com>
Date: Wed, 01 Feb 2006 15:54:46 -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: TSR issues (with code)
Reply-To: djgpp AT delorie DOT com

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

Hi, I'm actually porting an application from Linux, back to
DOS (think along the lines of multi-threaded apache type daemon
but not nearly as large or complex), and I've got everything working
flawlessly _except_ the TSR portion.  Basically, I've separated the
code out for testing to rule out anything within my application
(test code ~250 lines, took out threading/context switches).  I've based
the TSR code off of the standard Charles Sandmann DJGPP TSR.

I've read everywhere about not making DOS calls within a TSR,
but this is a necessary evil.  I read that you _can_ make
DOS calls if you check the InDos and CritErr flags, and also
add an interrupt handler to 0x28 as well to hook the Dos
IDLE interrupt, since it is safe to execute DOS calls if
InDos is 0x01 and CritErr is 0x00 within an 0x28 DOS IDLE
handler.  (The only call I'm making that might call a DOS
interrupt is write(), unless dosmemget() does and I don't
know it).  I also call 'cli' upon entry to my interrupt handler
to disable interrupts, and 'sti' upon exit to re-enable them.

What's happening is this ... in WindowsXP in a DOS box, it runs
flawlessly (it completes and unloads itself).  In DOS 6.22, it
gets called around 1000 times, then DOS entirely locks up
(the entire test ends at 10,000 and it calls write() every 100
times the interrupt is triggered where InDos and CritErr are 0x00).
My only thought is that I must not be checking the InDos or CritErr
flags properly... I didn't see any code on how to do it from within
protected mode, so I simply did a __dpmi_int call to get the address of
each, and use dosmemget()  to retrieve the one-byte indicators
for each, though maybe my usage is in error.

I've attached the code to this message and compile it as:
gcc -Wall -o testtsr.exe testtsr.c tsr.c
I would greatly appreciate any insight anyone can provide!

Thanks!
-Brad

--------------090205050009050504090804
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 <unistd.h>
#include <sys/time.h>
#include "tsr.h"

static int cnt = 0;

void tsr_callback(void)
{
	cnt++;
	if ((cnt % 100) == 0) {
		write(1, "100 more\r\n", 10);
	}
	if (cnt == 10000) {
		write(1, "removing tsr...\r\n", 17);
		remove_tsr();
		write(1, "removed!\r\n", 10);
	}
}

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

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

#if defined(__DJGPP__) || defined(__WATCOMC__)
/* DJGPPTSR, Nov 1995 Charles Sandmann (sandmann AT clio DOT rice DOT edu)
   Updated Oct 2002.

   ABSOLULTELY NO WARRANTY.  May be redistributed or copied without restriction.

   An example of a DJGPP TSR.  This routine changes the video attribute of the
   character in the upper right of the screen once per tick (from protected
   mode).  The DPMI provider will be forced to stay resident after this image
   exits.  This code also shows an undocumented way to suppress the exception
   code loading to decrease the image footprint size.  Not optimal - you can
   do the same thing with a single GAS file with a much smaller image.  Left 
   as an exercise for the user.  Have fun!  


   Trying to modify to allow DOS calls from within TSR...
	- Brad House 2006
*/

#  ifdef __DJGPP__
#    include <go32.h>
#  endif

#  include <stdio.h>
#  include <stdlib.h>
#  include <string.h>
#  include <io.h>

#  ifdef __DJGPP__
//#    define USE_NEARPTR 1
#    include <dpmi.h>
#    include <sys/farptr.h>
#    ifdef USE_NEARPTR
#      include <sys/nearptr.h>
#    endif /* USE_NEARPTR */
#    include <crt0.h>
#    include <go32.h>
#    include <pc.h>
#    include <sys/exceptn.h>
#  endif

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

#  include "tsr.h"

#  ifdef __DJGPP__
/* FLAG to lock all memory */
#    ifdef USE_NEARPTR
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY | _CRT0_FLAG_NEARPTR;
#    else
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY;
#    endif /* USE_NEARPTR */
#  endif /* __DJGPP__ */

static volatile int indos_offset;    /* saved INDOS flag address */
static volatile int critical_offset; /* saved critical error flag */
static volatile int in_int28=0; /* check to see if we're in an int28 call */
static volatile int in_callback=0; /* check to see if it's trying to reenter */
static mycallback int_callback=NULL;
static int tsr_is_active = 0;

#  ifdef __DJGPP__

/* Place to store old interrupt vectors */
static _go32_dpmi_seginfo old_int8_vector;
static _go32_dpmi_seginfo old_int28_vector;

/* Calls int 21 ax 0x3100 to tell app to terminate and stay resident */
static void keep(unsigned char status, unsigned size)
{
	__dpmi_regs regs;

	_farsetsel(_dos_ds);

	/* Keep size default is current PSP block size */
	if(_farnspeekw(_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 */
		regs.x.dx = (_go32_info_block.size_of_transfer_buffer + 256) / 16;
	else
		regs.x.dx = _farnspeekw(_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 < regs.x.dx)
		regs.x.dx = size;

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

#  endif /* __DJGPP__ */

static unsigned char _peekb(int dosoffset)
{
#  ifdef __DJGPP__
#    ifdef USE_NEARPTR
	return(*((char *)dosoffset + __djgpp_conventional_base));
#    else /* USE_NEARPTR */
	unsigned char c;
	dosmemget(dosoffset, sizeof(c), &c);
	return(c);
#    endif /* USE_NEARPTR */
#  elif defined(__WATCOMC__) 
	return(*((char *)dosoffset)); /* WATCOM C */
#  else
	return(-1);
#  endif /* __DJGPP__, else __WATCOMC__ */
}


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

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

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

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

void myint28_function(void)
{
	asm("cli");   /* Block interrupts */
	//asm("pusha");  

	/* Increment int28 cntr so we know we're being
	 * called from the int28 callback */
	in_int28++;
	if (tsr_execute_allowed() && !in_callback) {
		in_callback++;
		(*int_callback)();
		in_callback--;
	}

	/* Decrement counter as we exit */
	in_int28--;	

	//asm("popa");
	asm("sti"); /* Unblock interrupts */
}

void myint8_function(void)
{
	asm("cli"); /* Block interrupts */
	//asm("pusha");
	if (tsr_execute_allowed() && !in_callback) {
		in_callback++;
		(*int_callback)();
		in_callback--;
	}
	//asm("popa");
	asm("sti"); /* Unblock interrupts */
}

int create_tsr(mycallback hook)
{
#  ifdef __DJGPP__
	_go32_dpmi_seginfo pmint8, pmint28;

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

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

#    ifdef USE_NEARPTR
	if (!__djgpp_nearptr_enable()) {
		printf("Nearptr support does not work for this system,\r\n"
				"please recompile without nearptr support!\r\n");
		return(0);
	}
#    endif /* USE_NEARPTR */

	printf(	"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));

	/* Timer interrupt */
	if (_go32_dpmi_get_protected_mode_interrupt_vector(TIMER_INTERRUPT, &old_int8_vector) != 0) {
		printf("Unable to get old int8 vector\r\n");
		return(0);
	}

	/* DOS idle interrupt, as DOS is primarily in this state, the
	 * indos flag could be 0x01 and we'd still be allowed to execute
	 * as long as the critical error flag is not set */ 
	if (_go32_dpmi_get_protected_mode_interrupt_vector(IDLEDOS_INTERRUPT, &old_int28_vector) != 0) {
		printf("Unable to get old int28 vector\r\n");
		return(0);
	}

	int_callback = hook;
	
	pmint8.pm_selector = _go32_my_cs(); /* Should this be _my_cs() ?? */
	pmint8.pm_offset = (int)myint8_function;
	_go32_dpmi_chain_protected_mode_interrupt_vector(TIMER_INTERRUPT, &pmint8);


	pmint28.pm_selector = _go32_my_cs(); /* Should this be _my_cs() ?? */
	pmint28.pm_offset = (int)myint28_function;
	_go32_dpmi_chain_protected_mode_interrupt_vector(IDLEDOS_INTERRUPT, &pmint28);


	printf("*******Installing as TSR*******\r\n");
	tsr_is_active = 1;
	__djgpp_exception_toggle();	/* Only needed if exceptions linked */
	keep(0, 0);			/* Keep Transfer Buffer */
#  endif
	return(0);
}

int remove_tsr()
{
#  ifdef __DJGPP__
	/* Restore old vector, people better be removing TSR's in
	 * reverse order (as is standard in DOS behavior!) */
	if (tsr_is_active) {
		_go32_dpmi_set_protected_mode_interrupt_vector(TIMER_INTERRUPT, &old_int8_vector);
		_go32_dpmi_set_protected_mode_interrupt_vector(IDLEDOS_INTERRUPT, &old_int28_vector);
		tsr_is_active = 0;
	}
#  endif
	return(1);
}


#endif /* __DJGPP__ || __WATCOMC__ */

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

#ifndef __TSR_H__
#  define __TSR_H__
#  if defined(__DJGPP__) || defined(__WATCOMC__)

typedef void (*mycallback)(void);
int create_tsr(mycallback hook);
int remove_tsr();

#  endif /* __DJGPP__ || __WATCOMC__ */
#endif

--------------090205050009050504090804--

- Raw text -


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