www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1994/09/25/23:16:59

Date: Sun, 25 Sep 1994 18:10:09 -0700 (PDT)
From: "Frederick W. Reimer" <fwreimer AT crl DOT com>
Subject: Re: es:di points to....
To: Kimberley Burchett <OKRA AT max DOT tiac DOT net>
Cc: DJGPP Mailing List <djgpp AT sun DOT soe DOT clarkson DOT edu>

This will be a long reply, but I think it answers your questions...

On Sun, 25 Sep 1994, Kimberley Burchett wrote:
>   'lo there. 
>   I've got to do two things with es:di.  First I have to get it to point 
> to a function I want called by a real-mode function, and second I have to 
> get it to point to an array of data.
>   I have a feeling that there will be a different approach for the two 
> problems.  I'm thinking I'll need some kind of real-mode function that 
> will call my protected-mode one for the first problem and I'll need a 
> function that allocates lower 640k memory and copies to it for the second 
> one.  For both problems, I'll need to figure out how to load es:di with a 
> segment and offset.
>   Also, I need to make sure that the registers will be preserved when my 
> function is called and somehow need to access them - should I use the 
> inline assembler or is there a C function to load the registers into a 
> struct?

First, how is the real mode program going to get control of the CPU?  If 
it's a TSR that hooks an interrupt, then it's easy.  I've cannibalized 
the pktdrvr.c program included in the distribution (in 
samples/dpmi/pktdrvr.c I believe).  This sample program is an interface 
to a packet driver written to FTP's packet driver specs.  It has 
requirements similar to yours.  First, it has to pass the (real mode) TSR 
the address of a callback function that is called when a packet is read 
from the network.  Because it's a real mode TSR, it expects to call a 
real mode function.  We have to allocate a real mode callback stub that 
will call our protected mode function when it is called.  To do this you 
need a _go32_dpmi_seginfo struct, and need to set the pm_offset member to 
the address of your protected mode function.  You then call 
_go32_dpmi_allocate_real_mode_callback_retf passing it the address of 
your _go32_dpmi_seginfo struct and a _go32_dpmi_registers struct.  It 
allocates the real mode stub and puts its address in the 
_go32_dpmi_seginfo rm_segment and rm_offset members.  You can pass the 
value of rm_segment and rm_offset to your real mode program somehow, 
maybe via the transfer buffer as explained below.  The stub program 
uses the _go32_registers struct to pass your protected mode program the 
values of ALL the registers at the time the real mode stub was called.  
That's how you can get the values of the registers that the real mode 
program passes your protected mode function.  When you are done (you know 
that the real mode program will no longer call your function), you should 
free the callback stub with _go32_dpmi_free_real_mode_callback function.

To access your array...  The pktdrvr.c program has a similar 
requirement.  You should be able to use the transfer buffer to pass data 
back and forth between your real mode and protected mode programs.  If 
there is a problem with this, or you just don't feel comfortable useing 
the transfer buffer, you can allocate dos memory and use that address.  
The pktdrvr.c program also does this, but I didn't include the 
appropriate functions here.  To use the transfer buffer, simply compute 
the offset and segment from the 
_go32_info_block.linear_address_of_transfer_buffer as shown below.  This 
is the real sticky point, unless your real mode program is a TSR hooking 
an interrupt, how are you going to pass it the addresses??  All examples 
here interface with the real mode program (TSR) via _go32_simulate_int.  
I have no idea how you would pass the information otherwise.

The program below is the modified (i.e., shortened) pktdrvr.c program in 
the standard distribution with comments added by me.  You SHOULD have the 
complete program available to you, if you need the "full picture."

Hope this helps.  If you have any questions, or anyone finds any fault 
with what I said, please let me know (I'd like to know if I have these 
functions figured out yet or not!).

------------------------------------------------------------
#include <go32.h>
#include <dos.h>
#include <dpmi.h>

/* to read data from your real mode program, pass it the address of the
    transfer buffer like below.  I believe (but am not sure) that the
    transfer buffer is used for other things, such as file reads, but
    it should be safe (no guarentee).  When your real mode program
    returns, do a dosmemget like below to copy the data into protected
    mode space.
*/
void pd_get_etheraddr(int v, char *buf, int len)
{
  _go32_dpmi_registers reg;
  memset(&reg, 0, sizeof(reg));
  reg.h.ah = 6;
  reg.x.bx = 0;
  reg.x.di = _go32_info_block.linear_address_of_transfer_buffer & 15;
  reg.x.es = _go32_info_block.linear_address_of_transfer_buffer >> 4;
  reg.x.cx = len;
  _go32_dpmi_simulate_int(v, &reg);
  dosmemget(_go32_info_block.linear_address_of_transfer_buffer, len, buf);
}

/* you can use the same method to pass the real mode program data from your
    program.  Simply reverse the order, write your data to the transfer
    buffer before calling your real mode program (in this case via an
    real mode interrupt).
*/
void pd_send(int v, void *packet, int length)
{
  _go32_dpmi_registers reg;
  memset(&reg, 0, sizeof(reg));
  reg.h.ah = 4;
  reg.x.si = _go32_info_block.linear_address_of_transfer_buffer & 15;
  reg.x.ds = _go32_info_block.linear_address_of_transfer_buffer >> 4;
  reg.x.cx = length;
  dosmemput(packet, length, _go32_info_block.linear_address_of_transfer_buffer);
  _go32_dpmi_simulate_int(v, &reg);
}


/* to have a real mode program call one of your protected mode functions,
    use a method similar to the following.  create a function that takes
    a pointer to a _go32_dpmi_registers struct and returns void.  you will
    also need to allocate a global _go32_dpmi_registers struct and a
    _go32_dpmi_seginfo struct, like below.  The pd_do function sets
    everything up.
*/

_go32_dpmi_registers rmcb_registers;
_go32_dpmi_seginfo rmcb_seginfo;
void rmcb(_go32_dpmi_registers *regs)
{
    /* do whatever you want in this protected mode function, which can
        be called by a real mode program via
            rmcb_seginfo.rm_segment:rmcb_seginfo.rm_offset
    */
}

void pd_do(int v)
{
  int i;

    /* set callback address so that go32 can allocate a callback */
  rmcb_seginfo.pm_offset = (int)rmcb;
  if ((i=_go32_dpmi_allocate_real_mode_callback_retf(&rmcb_seginfo, &rmcb_registers)) != 0)
  {
    printf("Error: cannot allocate real mode callback, error=%04x\n", i);
    return;
  }
  printf("real mode callback is at %04x:%04x\n", rmcb_seginfo.rm_segment, rmcb_seginfo.rm_offset);

    /* you can now use rmcb_seginfo.rm_segment as the segment and
        rmcb_seginfo.rm_offset in the real mode program to call your
        protected mode function `rmcb'.  Pass these values somehow to
        your real mode program and have it to a far call to these
        addresses.
    */

    /* you must free the callback when you are done */

  _go32_dpmi_free_real_mode_callback(&rmcb_seginfo);
  printf("real mode callback released\n");
}
-------------------------------------------------------------


Fred Reimer

+-------------------------------------------------------------+
| The views expressed in the above are solely my own, and are |
| not necessarily the views of my employer.  Have a nice day! |
| PGP2.6 public key available via `finger fwreimer AT crl DOT com`   |
+-------------------------------------------------------------+



- Raw text -


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