delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1998/09/10/03:35:46

Date: Thu, 10 Sep 1998 10:34:15 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
To: Nick Bull <nick AT imat DOT demon DOT co DOT uk>
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: <Pine.SUN.3.91.980910103405.8350J-100000@is>
MIME-Version: 1.0

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));
      };

- Raw text -


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