delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2006/02/05/00:08:11

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
Message-ID: <43E587DC.6080801@mainstreetsoftworks.com>
Date: Sun, 05 Feb 2006 00:06:36 -0500
From: Brad House <brad AT mainstreetsoftworks DOT com>
User-Agent: Mail/News 1.5 (X11/20060201)
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>
In-Reply-To: <0naeb3-s442.ln1@news.infowest.com>
Reply-To: djgpp AT delorie DOT com

Wow, thanks!  I think the crutch of the problem was I was
using ds instead of es for the indos flag ... stupid stupid.
Also, the realmode interrupt handler for int28 greatly helps
my other needs as far as also needing to hook the BIOS calls
as well. I need to create my own 'inBios' flag in order to make sure
my TSR is bullet-proof (since I may need to call DOS and BIOS
calls from within my TSR), so hooking those, incrementing an
inbios counter, calling the previous hooks, then decrementing
the counter should do that as per the Art of Assembly DOS
reference on TSRs:
  http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH18/CH18-3.html

Once I get that code squared away (and hopefully working flawlessly),
I'll be returning that code to the public domain, so the next
guy should be able to just plug the code into any relevant
program.

Thanks again for your amazing assistance!
Should be able to get the code reworked and tested on Monday!

-Brad

Rod Pemberton wrote:
> "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 -


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