Date: Sun, 25 Sep 1994 18:10:09 -0700 (PDT) From: "Frederick W. Reimer" Subject: Re: es:di points to.... To: Kimberley Burchett Cc: DJGPP Mailing List 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 #include #include /* 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` | +-------------------------------------------------------------+