Mail Archives: djgpp/1994/09/25/23:16:59
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(®, 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, ®);
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(®, 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, ®);
}
/* 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 -