Mail Archives: djgpp/2006/02/04/09:31:42
"Brad House" <brad AT mainstreetsoftworks DOT com> wrote in message
news:43E3884C DOT 8050308 AT mainstreetsoftworks DOT com...
> Ok, doing realmode reflection doesn't look like it's too bad then...
> And you suggest using _go32 function instead of __dpmi functions,
> so to chain the interrupt vector, how would that work, it seems as
> though there is no _chain_ routine, would I simply call the old
> dos realmode int's pm_offset assuming the _go32_dpmi wrappers
> made such a routine for me? This is how I think it _should_
> look:
I've got it working. I'll inline all three after my signature.
1) DIR/S lockup is due to write() calling a dos interrupt
2) for INDOS it's, r.x.es. You used ds.
3) my preference, I changed r.x.es*16+r.x.bx to (r.x.es<<4)|r.x.bx
4) replaced write with custom routine owrite()
Rod Pemberont
----
#ifndef __TSR_H__
#define __TSR_H__
typedef void (*mycallback)(void);
int create_tsr(mycallback hook);
int remove_tsr();
void owrite(char *);
//#define DEBUG
#endif
----
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/nearptr.h>
#include "tsr.h"
static int cnt=0,x=0,y=0;
void owrite (char *p)
{
char line[80];
char *screen = (char *)0xB8000;
int i;
screen-=__djgpp_base_address;
memset(line,0,sizeof(line));
sprintf(line,"%s",p);
for (i=0;i<strlen(line);i++)
{
if(line[i]!='\n')
{
screen[x*80*2+2*y]=line[i];
screen[x*80*2+2*y+1]=0x6F;
y++;
}
if(y==80||line[i]=='\n')
{
y=0;
x++;
if(x==25)
x=0;
}
}
};
void tsr_callback(void)
{
#ifdef DEBUG
owrite("tsr_call");
#endif
cnt++;
if ((cnt % 100) == 0)
{
owrite("100 more\n");
}
if (cnt == 10000)
{
owrite("removing tsr...\n");
remove_tsr();
owrite("removed!\n");
}
}
int main(void)
{
__djgpp_nearptr_enable();
owrite("Creating tsr...\n");
if (!create_tsr(tsr_callback))
{
owrite("failed\n");
return(1);
}
/* Should never actually get here, because */
/* we terminated and stayed resident */
return(0);
}
----
/* 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <go32.h>
#include <dpmi.h>
#include <crt0.h>
#include <dos.h>
#include <pc.h>
#include <unistd.h>
#include <sys/exceptn.h>
#include <sys/farptr.h>
#include "tsr.h"
#define asm_cli disable
#define asm_sti enable
#define TIMER_INTERRUPT 0x1c
#define IDLEDOS_INTERRUPT 0x28 /* DOS idle interrupt */
/* FLAG to lock all memory */
int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY|_CRT0_FLAG_UNIX_SBRK;
volatile int indos_offset; /* saved INDOS flag address */
volatile int critical_offset; /* saved critical error flag */
volatile int in_int28=0; /* check to see if we're in an int28 call */
volatile int in_callback=0; /* check to see if it's trying to reenter */
mycallback int_callback=NULL;
/* Place to store old interrupt vectors */
_go32_dpmi_seginfo old_int8_vector;
_go32_dpmi_seginfo old_int28_vector;
_go32_dpmi_registers r;
/* Calls int 21 ax 0x3100 to tell app to terminate and stay resident */
void keep(unsigned char status, unsigned size)
{
#ifdef DEBUG
owrite("keep ");
#endif
/* 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);
}
unsigned char _peekb(int dosoffset)
{
unsigned char c;
#ifdef DEBUG
owrite("_peekb ");
#endif
dosmemget(dosoffset, sizeof(c), &c);
return(c);
}
int tsr_execute_allowed()
{
char indos, critical;
#ifdef DEBUG
owrite("tsr_exec ");
#endif
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)
{
#ifdef DEBUG
owrite("\nmyint28 ");
#endif
asm_cli(); /* Block interrupts */
/* 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_sti(); /* Unblock interrupts */
/* Chain interrupt */
r.x.cs = old_int28_vector.rm_segment;
r.x.ip = old_int28_vector.rm_offset;
_go32_dpmi_simulate_fcall_iret(&r);
}
void myint8_function(void)
{
#ifdef DEBUG
owrite("\nmyint8 ");
#endif
asm_cli(); /* Block interrupts */
if(tsr_execute_allowed()&&!in_callback)
{
in_callback++;
(*int_callback)();
in_callback--;
}
asm_sti(); /* Unblock interrupts */
/* Chain interrupt */
r.x.cs = old_int8_vector.rm_segment;
r.x.ip = old_int8_vector.rm_offset;
_go32_dpmi_simulate_fcall_iret(&r);
}
int create_tsr(mycallback hook)
{
_go32_dpmi_seginfo pmint8, pmint28;
#ifdef DEBUG
owrite("cre_tsr ");
#endif
/* Locate INDOS flag */
memset(&r, 0, sizeof(r));
r.h.ah = 0x34;
__dpmi_int(0x21,&r);
if(r.x.flags&1)
{
printf("Unable to get indos flag\n");
return(1);
}
indos_offset=(r.x.es<<4)|r.x.bx;
/* Locate Critical Error Flag */
memset(&r, 0, sizeof(r));
r.x.ax=0x5D06;
__dpmi_int(0x21,&r);
if(r.x.flags&1)
{
printf("Unable to get criterr flag\n");
return(1);
}
critical_offset=(r.x.ds<<4)|r.x.si;
printf( "InDos addr: 0x%x val: 0x%x\n"
"Critical Err addr: 0x%x val: 0x%x\n",
(int)indos_offset, _peekb(indos_offset),
(int)critical_offset, _peekb(critical_offset));
int_callback = hook;
/* Timer interrupt */
_go32_dpmi_get_real_mode_interrupt_vector(TIMER_INTERRUPT,
&old_int8_vector);
pmint8.pm_offset = (unsigned long)&myint8_function;
_go32_dpmi_allocate_real_mode_callback_iret(&pmint8, &r);
_go32_dpmi_set_real_mode_interrupt_vector(TIMER_INTERRUPT, &pmint8);
/* 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 */
_go32_dpmi_get_real_mode_interrupt_vector(IDLEDOS_INTERRUPT,
&old_int28_vector);
pmint28.pm_offset = (unsigned long)&myint28_function;
_go32_dpmi_allocate_real_mode_callback_iret(&pmint28, &r);
_go32_dpmi_set_real_mode_interrupt_vector(TIMER_INTERRUPT, &pmint28);
printf("*******Installing as TSR*******\n");
__djgpp_exception_toggle(); /* Only needed if exceptions linked */
keep(0, 0); /* Keep Transfer Buffer */
return(0);
}
int remove_tsr()
{
/* Restore old vector, people better be removing TSR's in */
/* reverse order (as is standard in DOS behavior!) */
#ifdef DEBUG
owrite("rem_tsr ");
#endif
_go32_dpmi_set_real_mode_interrupt_vector(TIMER_INTERRUPT,
&old_int8_vector);
_go32_dpmi_set_real_mode_interrupt_vector(IDLEDOS_INTERRUPT,
&old_int28_vector);
return (0);
}
----
- Raw text -