Date: Thu, 10 Sep 1998 10:34:15 +0300 (IDT) From: Eli Zaretskii To: Nick Bull cc: djgpp AT delorie DOT com Subject: Re: Calling Software interrupts In-Reply-To: <905271833.2795.0.nnrp-05.d4e48d0d@news.demon.co.uk> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk On Tue, 8 Sep 1998, Nick Bull wrote: > int ReadLong(DWORD loc, WORD secnum, char far *buf) > { > struct ReadL { > struct ReqHdr req; > BYTE mode; > void far *address; > WORD secnum; > DWORD loc; > BYTE readmode; > BYTE skip[2]; > } cmd; > > // snip // > > cmd.address=buf; > > // snip // > } > > I think this is where the problem is. I've removed the "char far *buf" from > the arguments and the "far" from the structure, but I think I'm running into > problems here. The function should call an interrupt in the MSCDEX driver > that fills buf with data. All of my other interrupt calls are working OK, > but they don't fill any memory with information. Can anyone help ? What am > I doing wrong ? This is a bit tricky. First, every buffer that is used to communicate with a real-mode driver needs to be in conventional memory. Second, you must change the declaration of the struct, for it to work. I attach below a section from the next version of the DJGPP FAQ list (to be released in a few days) which should explain that. If anything there is unclear, please ask. > buf is allocated using a malloc, and I know my calling procedure for the > interrupt works (copies the command block to dos memory and calls using > __dpmi_interrupt). Help ! You need to plug into the cmd.address member the seg:off address of the buffer in CONVENTIONAL memory, otherwise MSCDEX won't be able to access it. Here's one way of doing this, assuming that you change the struct definition as the FAQ excerpt below suggests: int dummy; /* Put the required memory size in paragraphs instead of NPARA below. */ int buf_seg = __dpmi_allocate_dos_memory (NPARA, &dummy); if (buf_seg == -1) /* error action */ else { cmd.address_seg = buf_seg; cmd.address_off = 0; /* If you need to put some data into cmd.address, copy it here from the buf argument to the conventional memory block using `dosmemput'. */ } This assumes that the struct members that replace the cmd.address member are called cmd.address_off and cmd.address_seg, see the FAQ advice below. After calling `__dpmi_int', you will have to use `dosmemget' or `_farpeekX' functions to copy the data from the buffer in conventional memory into your variable `buf'. --------------------- from the FAQ ---------------------------------- 18.5 How to move structs returned by real-mode services? ======================================================== **Q*: My program uses the contents of a structure returned by a VBE function, but some of the struct members are garbled!* *A*: Most probably, this happens because of incorrect declaration of the structure in your program. Many people copy a declaration from some real-mode program, and that is exactly what gets them into trouble. Here are some gotchas in this context: * The structure should be declared with `__attribute__((packed))', to prevent GCC from inserting gaps between some members to make them properly aligned for faster access (see how gcc aligns structs in Section 22.10). C programs can declare the entire struct with the packed attribute, but C++ programs will need to declare each member with it, see __attribute__((packed)) in Section 22.10. * If the real-mode struct has members which are pointers, you need to replace each pointer with a pair of an offset and a segment (in that order, due to Intel's little-endian byte order). This is because real-mode far pointers cannot be used as protected-mode pointers: you cannot dereference them to get access to the object they point to. Declaring them as a segment:offset pair will force you into correct usage, see below. * To use pointers which are members of the structure, you will have to employ some of the methods described in section about using the transfer buffer in Section 18.4. For example, to copy data whose real-mode address is returned in a struct, use `dosmemget' or one of the `_farpeekX' family of functions in conjunction with the `_dos_ds' selector, and don't forget to compute the linear address as `segment * 16 + offset'. * If the pointer is to a function, you will need to use the library function `__dpmi_simulate_real_mode_procedure_retf' to call it (don't forget to zero out the `.x.ss' and `.x.sp' members of the `__dpmi_regs' structure!). * Many real-mode compilers use 16-bit `int's, whereas in DJGPP, an `int' is 32-bit wide. You need to change the declaration of all struct members from `int' to `short', and from `unsigned' to `unsigned short'. For example, the following real-mode structure declaration: struct ncb { unsigned ncb_command; int ncb_status; char far *ncb_buffer; /* a far pointer to a buffer */ char ncb_name[32]; int far (*ncb_dispatch)(); /* a pointer to a far function */ }; should be converted to this in a DJGPP program: struct ncb { unsigned short ncb_command __attribute__((packed)); short ncb_status __attribute__((packed)); unsigned short ncb_buf_offset __attribute__((packed)); unsigned short ncb_buf_segment __attribute__((packed)); char ncb_name[32] __attribute__((packed)); unsigned short ncb_dispatch_offset __attribute__((packed)); unsigned short ncb_dispatch_segment __attribute__((packed)); };