------------------------------------------------------------------------------
---------------------- QLIB  For Watcom C/C++ --------------------------------
------------------------------------------------------------------------------

  This is the documentation for QLIB  for Watcom C/C++, henceforth
referred to as QLIB . QLIB is Copyright (c) 1996-1997, Peter Quiring.
All rights reserved.

Contents:
---------

1 - Overview
    1.0  - What are these functions?

2 - Supported DPMI INT 31h functions
    2.0  - Function 0000h - Allocate Descriptors
    2.1  - Function 0001h - Free Descriptor
    2.2  - Function 0002h - Segment to Descriptor
    2.3  - Function 0003h - Get Selector Increment Value
    2.4  - Function 0006h - Get Segment Base Address
    2.5  - Function 0007h - Set Segment Base Address
    2.6  - Function 0008h - Set Segment Limit
    2.7  - Function 0009h - Set Descriptor Access Rights
    2.8  - Function 000Ah - Create Alias Descriptor
    2.9  - Function 000Bh - Get Descriptor
    2.10 - Function 000Ch - Set Descriptor
    2.11 - Function 0100h - Allocate DOS Memory Block
    2.12 - Function 0101h - Free DOS Memory Block
    2.13 - Function 0102h - Resize DOS Memory Block
    2.14 - Function 0200h - Get Real Mode Interrupt Vector
    2.15 - Function 0201h - Set Real Mode Interrupt Vector
    2.16 - Function 0202h - Get Processor Exception Handler Vector
    2.17 - Function 0203h - Set Processor Exception Handler Vector
    2.18 - Function 0204h - Get Protected Mode Interrupt Vector
    2.19 - Function 0205h - Set Protected Mode Interrupt Vector
    2.20 - Function 0300h - Simulate Real Mode Interrupt
    2.21 - Function 0301h - Call Real Mode Procedure With Far Return Frame
    2.22 - Function 0302h - Call Real Mode Procedure With IRET Frame
    2.23 - Function 0303h - Allocate Real Mode Callback Address
    2.24 - Function 0304h - Free Real Mode Callback Address
    2.25 - Function 0305h - Get State Save/Restore Addresses
    2.26 - Function 0306h - Get Raw Mode Switch Addresses
    2.27 - Function 0400h - Get Version
    2.28 - Function 0500h - Get Free Memory Information
    2.29 - Function 0501h - Allocate Memory Block
    2.30 - Function 0502h - Free Memory Block
    2.31 - Function 0503h - Resize Memory Block

    2.31.1 - Function 0600h - Lock Memory Block
    2.31.2 - Function 0601h - UnLock Memory Block
    2.31.3 - Function 0xxxh - Lock All Memory

    2.32 - Function 0800h - Physical Address Mapping
    2.33 - Function 0801h - Free Physical Address Mapping
    2.34 - Function 0900h - Get and Disable Virtual Interrupt State
    2.35 - Function 0901h - Get and Enable Virtual Interrupt State
    2.36 - Function 0902h - Get Virtual Interrupt State
    2.37 - Function EEFFh - Get DOS Extender Information

3 - DPMI 'C' Wrappers

    3.0 - Allocate INT/IRQ Wrapper
    3.1 - Allocate RETF Callback Wrapper
    3.2 - Allocate IRET Callback Wrapper

4 - CallBack termination (ASM only)

    4.0 - Terminate Callback Routine (RETF stack frame)
    4.1 - Terminate Callback Routine (IRET stack frame)

------------------------------------------------------------------------------
------------------------------ 1 - Overview ----------------------------------
------------------------------------------------------------------------------

1.0 - What are these functions?:
--------------------------------

  The following DPMI 'C' callable functions are provided to easy the
process of calling the DPMI INT 31h server.  All services that return a
48bit pointer will return them in a struct.  The following structs are
defined in dpmi.h (dpmi.inc) in the QLIB include directories.

struct pmPROCstruct {
  word _sel;
  dword _off;
}

struct rmPROCstruct {
  word _seg;
  word _off;
}

There is also the callstruct which is used with DPMI functions 30xh.  This
struct is also in the include files.  This struct holds all the real mode
registers and segment registers.  See dpmi.h (dpmi.inc) for its layout.
When passing these structs, only pass their addresses only!
  ie:  _DPMI_getpmint(21h,&my_struct);

------------------------------------------------------------------------------
------------------- 2 - Supported DPMI INT 31h functions ---------------------
------------------------------------------------------------------------------

2.0 - Function 0000h - Allocate Descriptors:
--------------------------------------------

  Allocates one or more descriptors in the client's descriptor table. The
descriptor(s) allocated must be initialized by the application with other
function calls.

  word _DPMI_desc_alloc(word n);

In:
  n     = number of descriptors to allocate

Out:
  if successful:
    word     = base selector

  if failed:
    word     = 0xffff

Notes:
) If more that one descriptor was requested, the function returns a base
  selector referencing the first of a contiguous array of descriptors. The
  selector values for subsequent descriptors in the array can be calculated
  by adding the value returned by INT 31h function 0003h.

) The allocated descriptor(s) will be set to expand-up writeable data, with
  the present bit set and a base and limit of zero. The privilege level of the
  descriptor(s) will match the client's code segment privilege level.

2.1 - Function 0001h - Free Descriptor:
---------------------------------------

  Frees a descriptor.

  byte _DPMI_desc_free(word n);

In:
  n     = selector for the descriptor to free

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) Each descriptor allocated with INT 31h function 0000h must be freed
  individually with the function. Even if it was previously allocated as part
  of a contiguous array of descriptors.

) Under DPMI 1.0/VCPI/XMS/raw, any segment registers which contain the
  selector being freed are zeroed by this function.

2.2 - Function 0002h - Segment to Descriptor:
---------------------------------------------

  Converts a real mode segment into a protected mode descriptor.

  word _DPMI_seg2desc(word seg);

In:
  seg = real mode segment

Out:
  if successful:
    word = selector

  if failed:
    word = 0xffff

Notes:
) Multiple calls for the same real mode segment return the same selector.

) The returned descriptor should never be modified or freed.

2.3 - Function 0003h - Get Selector Increment Value:
----------------------------------------------------

  The Allocate Descriptors function (0000h) can allocate an array of
contiguous descriptors, but only return a selector for the first descriptor.
The value returned by this function can be used to calculate the selectors for
subsequent descriptors in the array.

  word _DPMI_selinc(void);

In:

Out:
  always successful:
    word = selector increment value

Notes:
) The increment value is always a power of two.

2.4 - Function 0006h - Get Segment Base Address:
------------------------------------------------

  Returns the 32bit linear base address from the descriptor table for the
specified segment.

  dword _DPMI_getbase(word sel);

In:
  sel = selector

Out:
  if successful:
    dword = 32bit linear base address of segment

  if failed:
    dword = 0xffffffff

Notes:
) Client programs must use the LSL instruction to query the limit for a
  descriptor.

2.5 - Function 0007h - Set Segment Base Address:
------------------------------------------------

  Sets the 32bit linear base address field in the descriptor for the specified
segment.

  byte _DPMI_setbase(word sel,dword base);

In:
  sel = selector
  base = 32bit linear base address of segment

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  but it is not guaranteed.

) We hope you have enough sense not to try to modify your current CS or SS
  descriptor.

2.6 - Function 0008h - Set Segment Limit:
-----------------------------------------

  Sets the limit field in the descriptor for the specified segment.

  byte _DPMI_setlimit(word sel,dword limit);

In:
  sel = selector
  limit = 32bit segment limit

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The value supplied to the function in CX:DX is the byte length of the
  segment-1.

) Segment limits greater than or equal to 1M must be page aligned. That is,
  they must have the low 12 bits set.

) This function has an implicit effect on the "G" bit in the segment's
  descriptor.

) Client programs must use the LSL instruction to query the limit for a
  descriptor.

) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  but it is not guaranteed.

) We hope you have enough sense not to try to modify your current CS or SS
  descriptor.

2.7 - Function 0009h - Set Descriptor Access Rights:
----------------------------------------------------

  Modifies the access rights field in the descriptor for the specified
segment.

  byte _DPMI_setrights(word sel,word rights);

In:
  sel = selector
  rights = access rights/type word

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The access rights/type word passed to the function has the following
  format:

    Bit: 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
       +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
       | G |B/D| 0 | ? |       ?       | 1 |  DPL  | 1 |C/D|E/C|W/R| A |
       +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

    G   - 0=byte granular, 1=page granular
    B/D - 0=default 16bit, 1=default 32bit
    DPL - must be equal to caller's CPL
    C/D - 0=data, 1=code
    E/C - data: 0=expand-up, 1=expand-down
          code: must be 0 (non-conforming)
    W/R - data: 0=read, 1=read/write
          code: must be 1 (readable)
    A   - 0=not accessed, 1=accessed
    0   - must be 0
    1   - must be 1
    ?   - ignored

) Client programs should use the LAR instruction to examine the access rights
  of a descriptor.

) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  selector will be reloaded. DPMI 0.9 may do this, but it is not guaranteed.

) We hope you have enough sense not to try to modify your current CS or SS
  descriptor.

2.8 - Function 000Ah - Create Alias Descriptor:
-----------------------------------------------

  Creates a new data descriptor that has the same base and limit as the
specified descriptor.

  word _DPMI_create_alias(word sel);

In:
  sel = selector

Out:
  if successful:
    word = data selector (alias)

  if failed:
    word = 0xffff

Notes:
) The selector supplied to the function may be either a data descriptor or
  a code descriptor. The alias descriptor created is always an expand-up
  writeable data segment.

) The descriptor alias returned by this function will not track changes to the
  original descriptor.

2.9 - Function 000Bh - Get Descriptor:
--------------------------------------

  Copies the descriptor table entry for the specified selector into an 8 byte
buffer.

  byte _DPMI_getdesc(word sel,void *buf);

In:
  sel = selector
  buf = 8 byte buffer

Out:
  if successful:
    buffer contains descriptor
    byte = 0x00

  if failed:
    byte = 0xff

2.10 - Function 000Ch - Set Descriptor:
---------------------------------------

  Copies the contents of an 8 byte buffer into the descriptor for the
specified selector.

  byte _DPMI_setdesc(word sel,void *buf);

In:
  sel = selector
  buf = 8 byte buffer containing descriptor

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

) The descriptors access rights/type word at offset 5 within the descriptor
  follows the same format and restrictions as the access rights/type parameter
  CX to the Set Descriptor Access Rights function (0009h).

) Under DPMI 1.0/VCPI/XMS/raw, any segment register which contains the
  selector specified in register BX will be reloaded. DPMI 0.9 may do this,
  but it is not guaranteed.

) We hope you have enough sense not to try to modify your current CS or SS
  descriptor or the descriptor of the buffer.

2.11 - Function 0100h - Allocate DOS Memory Block:
--------------------------------------------------

  Allocates low memory through DOS function 48h and allocates it a descriptor.

  word _DPMI_dos_alloc(word siz);

In:
  siz = paragraphs to allocate

Out:
  if successful:
    word = protected mode selector for memory block

  if failed:
    word = 0xffff

Notes:
) Use _DPMI_getbase() to find where the segment starts (below 1MB)

2.12 - Function 0101h - Free DOS Memory Block:
----------------------------------------------

  Frees a low memory block previously allocated by function 0100h.

  byte _DPMI_dos_free(word sel);

In:
  sel = protected mode selector for memory block

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

2.13 - Function 0102h - Resize DOS Memory Block:
------------------------------------------------

  Resizes a low memory block previously allocated by function 0100h

  byte _DPMI_dos_resize(word sel,word siz);

In:
  sel = protected mode selector for memory block
  siz = new block size in paragraphs

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

2.14 - Function 0200h - Get Real Mode Interrupt Vector:
-------------------------------------------------------

  Returns the real mode segment:offset for the specified interrupt vector.

  void _DPMI_getrmint(byte v,struct rmPROCstruct *rf);

In:
  v = interrupt number
  rf => buffer for rmode proc pointer

Out:
  always successful:
    rf => filled in with vector

Notes:
) The value returned in rf._seg is a real mode segment address, not a
  protected mode selector.

2.15 - Function 0201h - Set Real Mode Interrupt Vector:
-------------------------------------------------------

  Sets the real mode segment:offset for the specified interrupt vector.

  void _DPMI_setrmint(byte v,struct rmPROCstruct *rf);

In:
  v = interrupt number
  rf => buffer for rmode proc pointer

Out:
  always successful:
    
Notes:
) The value passed in CX must be a real mode segment address, not a protected
  mode selector. Consequently, the interrupt handler must either reside in
  DOS memory (below the 1M boundary) or the client must allocate a real mode
  callback address.

2.16 - Function 0202h - Get Processor Exception Handler Vector:
---------------------------------------------------------------

  Returns the address of the current protected mode exception handler for the
specified exception number.

  byte _DPMI_getexc(byte v,struct pmPROCstruct *pf);

In:
  v = exception number (00h-1fh)
  pf => buffer for exception handler addr

Out:
  if successful:
    pf => filled in with exception handler addr
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) PMODE/W handles exceptions under clean/XMS/VCPI environments. Under a DPMI
  environment, exception handling is provided by the DPMI host.

) PMODE/W only traps exceptions 0 through 14. The default behavior is to
  terminate execution and do a debug dump. PMODE/W will terminate on
  exceptions 0, 1, 2, 3, 4, 5, and 7, instead of passing them down to the
  real mode handlers as DPMI specifications state.

2.17 - Function 0203h - Set Processor Exception Handler Vector:
---------------------------------------------------------------

  Sets the address of a handler for a CPU exception or fault, allowing a
protected mode application to intercept processor exceptions.

  byte _DPMI_setexc(byte v,struct pmPROCstruct *pf);

In:
  v = exception number (00h-1fh)
  pf => new exception handler addr

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) PMODE/W handles exceptions under clean/XMS/VCPI environments. Under a DPMI
  environment, exception handling is provided by the DPMI host.

) PMODE/W only traps exceptions 0 through 14. The default behavior is to
  terminate execution and do a debug dump. PMODE/W will terminate on
  exceptions 0, 1, 2, 3, 4, 5, and 7, instead of passing them down to the
  real mode handlers as DPMI specifications state.

) If you wish to hook one of the low 8 interrupts, you must hook it as an
  exception. It will not be called if you hook it with function 0205h.

2.18 - Function 0204h - Get Protected Mode Interrupt Vector:
------------------------------------------------------------

  Returns the address of the current protected mode interrupt handler for the
specified interrupt.

  void _DPMI_getpmint(byte v,struct pmPROCstruct *pf);

In:
  v = interrupt number
  pf => buffer for rmode proc pointer

Out:
  always successful:
    pf => filled in with vector

Notes:
) The value returned in pf._sel is a valid protected mode selector, not a
  real mode segment address.

2.19 - Function 0205h - Set Protected Mode Interrupt Vector:
------------------------------------------------------------

  Sets the address of the protected mode interrupt handler for the specified
interrupt.

  byte _DPMI_setpmint(byte v,struct pmPROCstruct *pf);

In:
  v = interrupt number
  pf => buffer of new rmode proc pointer

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The value passed in CX must be a valid protected mode selector, not a real
  mode segment address.

) If you wish to hook one of the low 8 interrupts, you must hook it as an
  exception. It will not be called if you hook it with function 0205h.

2.20 - Function 0300h - Simulate Real Mode Interrupt:
-----------------------------------------------------

  Simulates an interrupt in real mode. The function transfers control to the
address specified by the real mode interrupt vector. The real mode handler
must return by executing an IRET.

  byte _DPMI_do_int(byte v,struct callstruct *cb);

In:
  v = vector
  cb => callstruct pointer holding rmode registers for int call

Out:
  if successful:
    cb => registers after call
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The CS:IP in the real mode register data structure is ignored by this
  function. The appropriate interrupt handler will be called based on the
  value passed in BL.

) If the SS:SP fields in the real mode register data structure are zero, a
  real mode stack will be provided by the host. Otherwise the real mode SS:SP
  will be set to the specified values before the interrupt handler is called.

) The flags specified in the real mode register data structure will be put on
  the real mode interrupt handler's IRET frame. The interrupt handler will be
  called with the interrupt and trace flags clear.

) Values placed in the segment register positions of the data structure must
  be valid for real mode. That is, the values must be paragraph addresses, not
  protected mode selectors.

) The target real mode handler must return with the stack in the same state
  as when it was called. This means that the real mode code may switch stacks
  while it is running, but must return on the same stack that it was called
  on and must return with an IRET.

) When this function returns, the real mode register data structure will
  contain the values that were returned by the real mode interrupt handler.
  The CS:IP and SS:SP values will be unmodified in the data structure.

) It is the caller's responsibility to remove any parameters that were pushed
  on the protected mode stack.

2.21 - Function 0301h - Call Real Mode Procedure With Far Return Frame:
-----------------------------------------------------------------------

  Simulates a FAR CALL to a real mode procedure. The called procedure must
return by executing a RETF instruction.

  byte _DPMI_do_call_retf(struct callstruct *cb);

In:
  cb => callstruct pointer holding rmode registers for int call

Out:
  if successful:
    cb => registers after call
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The CS:IP in the real mode register data structure specifies the address of
  the real mode procedure to call.

) If the SS:SP fields in the real mode register data structure are zero, a
  real mode stack will be provided by the host. Otherwise the real mode SS:SP
  will be set to the specified values before the procedure is called.

) Values placed in the segment register positions of the data structure must
  be valid for real mode. That is, the values must be paragraph addresses, not
  protected mode selectors.

) The target real mode procedure must return with the stack in the same state
  as when it was called. This means that the real mode code may switch stacks
  while it is running, but must return on the same stack that it was called
  on and must return with a RETF and should not clear the stack of any
  parameters that were passed to it on the stack.

) When this function returns, the real mode register data structure will
  contain the values that were returned by the real mode procedure. The CS:IP
  and SS:SP values will be unmodified in the data structure.

) It is the caller's responsibility to remove any parameters that were pushed
  on the protected mode stack.

2.22 - Function 0302h - Call Real Mode Procedure With IRET Frame:
-----------------------------------------------------------------

  Simulates a FAR CALL with flags pushed on the stack to a real mode routine.
The real mode procedure must return by executing an IRET instruction or a
RETF 2.

  byte _DPMI_do_call_iret(struct callstruct *cb);

In:
  v = vector
  cb => callstruct pointer holding rmode registers for int call

Out:
  if successful:
    cb => registers after call
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The CS:IP in the real mode register data structure specifies the address of
  the real mode procedure to call.

) If the SS:SP fields in the real mode register data structure are zero, a
  real mode stack will be provided by the host. Otherwise the real mode SS:SP
  will be set to the specified values before the procedure is called.

) The flags specified in the real mode register data structure will be put on
  the real mode procedure's IRET frame. The procedure will be called with the
  interrupt and trace flags clear.

) Values placed in the segment register positions of the data structure must
  be valid for real mode. That is, the values must be paragraph addresses, not
  protected mode selectors.

) The target real mode procedure must return with the stack in the same state
  as when it was called. This means that the real mode code may switch stacks
  while it is running, but must return on the same stack that it was called
  on and must return with an IRET or discard the flags from the stack with a
  RETF 2 and should not clear the stack of any parameters that were passed to
  it on the stack.

) When this function returns, the real mode register data structure will
  contain the values that were returned by the real mode procedure. The CS:IP
  and SS:SP values will be unmodified in the data structure.

) It is the caller's responsibility to remove any parameters that were pushed
  on the protected mode stack.

2.23 - Function 0303h - Allocate Real Mode Callback Address:
------------------------------------------------------------

  Returns a unique real mode segment:offset, known as a "real mode callback",
that will transfer control from real mode to a protected mode procedure.
Callback addresses obtained with this function can be passed by a protected
mode program to a real mode application, interrupt handler, device driver,
TSR, etc... so that the real mode program can call procedures within the
protected mode program.

  byte _DPMI_callstruct_alloc(struct rmPROCstruct *rf,
    struct pmPROCstruct *pf, struct callstruct *cb);

In:
  rf => buffer for segment:offset of real mode callback
  pf => selector:offset of protected mode procedure to call
  cb => 32h byte buffer for real mode register data
        structure to be used when calling the callback routine.

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) A descriptor may be allocated for each callback to hold the real mode SS
  descriptor. Real mode callbacks are a limited system resource. A client
  should release a callback that it is no longer using.

2.24 - Function 0304h - Free Real Mode Callback Address:
--------------------------------------------------------

  Releases a real mode callback address that was previously allocated with the
Allocate Real Mode Callback Address function (0303h).

  byte _DPMI_callback_free(struct rmPROCstruct *rf);

In:
  rf => segment:offset of real mode callback to be freed

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) Real mode callbacks are a limited system resource. A client should release
  any callback that it is no longer using.

2.25 - Function 0305h - Get State Save/Restore Addresses:
---------------------------------------------------------

  Returns the address of two procedures used to save and restore the state of
the current task's registers in the mode (protected or real) which is not
currently executing.

  word _DPMI_get_raw_state(struct rmPROCstruct *rf, struct pmPROCstruct *pf);

In:
  rf => buffer for rmode addr
  pf => buffer for pmode addr

Out:
  always successful:
    word = size of buffer in bytes required to save state
    rf   => segment:offset of real mode routine used to save/restore state
    pf   => selector:offset of protected mode routine used to save/restore
	     state

Notes:
) The real mode segment:offset returned by this function should be called
  only in real mode to save/restore the state of the protected mode registers.
  The protected mode selector:offset returned by this function should be
  called only in protected mode to save/restore the state of the real mode
  registers.

) Both of the state save/restore procedures are entered by a FAR CALL with the
  following parameters:

  AL       = 0 to save state
           = 1 to restore state
  ES:(E)DI = (selector or segment):offset of state buffer

  The state buffer must be at least as large as the value returned in AX by
  INT 31h function 0305h. The state save/restore procedures do not modify any
  registers. DI must be used for the buffer offset in real mode, EDI must be
  used in protected mode.

) Some DPMI hosts and VCPI/XMS/raw will not require the state to be saved,
  indicating this by returning a buffer size of zero in AX. In such cases,
  that addresses returned by this function can still be called, although they
  will simply return without performing any useful function.

) Clients do not need to call the state save/restore procedures before using
  INT 31h function 0300h, 0301h, or 0302h. The state save/restore procedures
  are provided for clients that use the raw mode switch services only.

2.26 - Function 0306h - Get Raw Mode Switch Addresses:
------------------------------------------------------

  Returns addresses that can be called for low level mode switching.

  word _DPMI_get_raw_switch(struct rmPROCstruct *rf, struct pmPROCstruct *pf);

In:
  rf => buffer for rmode addr
  pf => buffer for pmode addr

Out:
  always successful:
    word = size of buffer in bytes required to save state
    rf  => segment:offset of real to protected mode switch procedure
    pf  => selector:offset of protected to real mode switch procedure

Notes:
) The real mode segment:offset returned by this function should be called
  only in real mode to switch to protected mode. The protected mode
  selector:offset returned by this function should be called only in protected
  mode to switch to real mode.

) The mode switch procedures are entered by a FAR JMP to the appropriate
  address with the following parameters:

  AX    = new DS
  CX    = new ES
  DX    = new SS
  (E)BX = new (E)SP
  SI    = new CS
  (E)DI = new (E)IP

  The processor is placed into the desired mode, and the DS, ES, SS, (E)SP,
  CS, and (E)IP registers are updated with the specific values. In other
  words, execution of the client continues in the requested mode at the
  address provided in registers SI:(E)DI. The values specified to be placed
  into the segment registers must be appropriate for the destination mode.
  That is, segment addresses for real mode, and selectors for protected mode.

  The values in EAX, EBX, ECX, EDX, ESI, and EDI after the mode switch are
  undefined. EBP will be preserved across the mode switch call so it can be
  used as a pointer. FS and GS will contain zero after the mode switch.

  If interrupts are disabled when the mode switch procedure is invoked, they
  will not be re-enabled by the host (even temporarily).

) It is up to the client to save and restore the state of the task when using
  this function to switch modes. This requires the state save/restore
  procedures whose addresses can be obtained with INT 31h function 0305h.

2.27 - Function 0400h - Get Version:
------------------------------------

  Returns the version of the DPMI Specification implemented by the DPMI host.
The client can use this information to determine what functions are available.

  word _DPMI_getver(void);
  word _DPMI_getflgs(void);
  byte _DPMI_getcpu(void);
  word _DPMI_getpics(void);

In:

Out:
  always successful:
    _DPMI_getver():
      word.hi = DPMI major version as a binary number (0x00 = 0)
      word.lo = DPMI minor version as a binary number (0x5a = 9)
    _DPMI_getflgs():
      word = flags:
	     Bits    Significance
             0       0 = host is 16bit (PMODE/W never runs under one of these)
		     1 = host is 32bit
	     1	     0 = CPU returned to V86 mode for reflected interrupts
		     1 = CPU returned to real mode for reflected interrupts
	     2	     0 = virtual memory not supported
		     1 = virtual memory supported
	     3-15    reserved
    _DPMI_getcpu():
      byte = processor type:
	     03h = 80386
	     04h = 80486
	     05h = 80586
	     06h-ffh = reserved
    _DPMI_getpics():
      word.hi = current value of master PIC base interrupt (low 8 IRQs)
      word.lo = current value of slave PIC base interrupt (high 8 IRQs)

Notes:
) The major and minor version numbers are binary, not BCD. So a DPMI 0.9
  implementation would return high as 0 and low as 5ah (90).

2.28 - Function 0500h - Get Free Memory Information:
2.29 - Function 0501h - Allocate Memory Block:
2.30 - Function 0502h - Free Memory Block:
2.31 - Function 0503h - Resize Memory Block:
----------------------------------------------

  Please use coreleft(), malloc(), free(), realloc().

2.31.1 - Function 0600h - Lock Memory Block:
--------------------------------------------

  Locks memory so that it will not be swapped to hard drive.  ISR should
be locked with this function.  Under RAW/XMS/VCPI where there is no
swapping this function simply always returns successful.

  byte _DPMI_lock_ram(dword off,dword siz);

In:
  off = linear address of memory
  siz = size of region in bytes

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

2.31.2 - Function 0601h - UnLock Memory Block:
----------------------------------------------

  Unlocks memory that was locked with func 600h.  Under RAW/XMS/VCPI where
there is no swapping this function simply always returns successful.

  byte _DPMI_unlock_ram(dword off,dword siz);

In:
  off = linear address of memory
  siz = size of region in bytes

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

2.31.3 - Function 0xxxh - Lock All Memory:
----------------------------------------------

  Attempts to lock all memory possible that this program owns.  If 'useonly'
equals '1' on call then the heap will be shruken to include only locked
memory.  If this is done you must not use malloc() or calloc() before
this call or it will fail.  This procedure just takes advantage of DPMI
func 600h a lot.

WARNING: This function can take as long as 3 min under Win95, depending
  on amount of RAM available, and I suggest you do NOT use it.
  Just take a look at the source code if you wish.
  I suggest you simply just lock your code and maybe some data, using this
  type of locking is crazy (altough it was used in easly stages of Quake,
  but soon they learned it twas not good and decided to only lock 1MB
  of image data cache - much faster).

  byte _DPMI_lock_all(byte useonly);

In:
  useonly = Only use locked memory?

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

2.32 - Function 0800h - Physical Address Mapping:
-------------------------------------------------

  Converts a physical address into a linear address. This functions allows the
client to access devices mapped at a specific physical memory address.
Examples of this are the frame buffers of certain video cards in extended
memory.

  dword _DPMI_phys_alloc(dword loc,dword siz);

In:
  loc = physical address of memory
  siz = size of region to map in bytes

Out:
  if successful:
    dword = linear address that can be used to access the physical memory

  if failed:
    dword = 0xffffffff

Notes:
) It is the caller's responsibility to allocate and initialize a descriptor
  for access to the memory.

) Clients should not use this function to access memory below the 1 MB
  boundary.

2.33 - Function 0801h - Free Physical Address Mapping:
------------------------------------------------------

  Releases a mapping of physical to linear addresses that was previously
obtained with function 0800h.

  byte _DPMI_phys_free(dword lin);

In:
  lin  = linear address returned by physical address mapping call

Out:
  if successful:
    byte = 0x00

  if failed:
    byte = 0xff

Notes:
) The client should call this function when it is finished using a device
  previously mapped to linear addresses with function _DPMI_phys_alloc().

2.34 - Function 0900h - Get and Disable Virtual Interrupt State:
----------------------------------------------------------------

  Disables the virtual interrupt flag and returns the previous state of it.

  byte _DPMI_cli(void);

In:

Out:
  always successful:
    byte = 0 if virtual interrupts were previously disabled
    byte = 1 if virtual interrupts were previously enabled

Notes:
) A client that does not need to know the prior interrupt state can execute
  the CLI instruction rather than calling this function. The instruction may
  be trapped by a DPMI host and should be assumed to be very slow.

2.35 - Function 0901h - Get and Enable Virtual Interrupt State:
---------------------------------------------------------------

  Enables the virtual interrupt flag and returns the previous state of it.

  byte _DPMI_sti(void);

In:

Out:
  always successful:
    byte = 0 if virtual interrupts were previously disabled
    byte = 1 if virtual interrupts were previously enabled

Notes:
) A client that does not need to know the prior interrupt state can execute
  the STI instruction rather than calling this function. The instruction may
  be trapped by a DPMI host and should be assumed to be very slow.

2.36 - Function 0902h - Get Virtual Interrupt State:
----------------------------------------------------

  Returns the current state of the virtual interrupt flag.

  byte _DPMI_getIF(void);

In:

Out:
  always successful:
    byte = 0 if virtual interrupts are disabled
    byte = 1 if virtual interrupts are enabled

Notes:
) This function should be used in preference to the PUSHF instruction to
  examine the interrupt flag, because the PUSHF instruction returns the
  physical interrupt flag rather than the virtualized interrupt flag. On some
  DPMI hosts, the physical interrupt flag will always be enabled, even when
  the hardware interrupts are not being passed through to the client.

2.37 - Function EEFFh - Get DOS Extender Information:
-----------------------------------------------------

  Returns information about the DOS extender.

  dword _DPMI_detect(struct pmPROCstruct *pf);
  byte _DPMI_getmode(void);

In:

Out:
  if successful:
    _DPMI_detect():
      dword = 'PMDW' (0x504D4457)  ;If DOS extender is PMODE/W
      pf => selector:offset of ASCIIZ copyright string
    _DPMI_getmode();
      byte = protected mode system type (0=raw, 1=XMS, 2=VCPI, 3=DPMI)

  if failed:
    _DPMI_detect():
      dword = 0xffffff
    _DPMI_getmode():
      byte = 0xff

Notes:
) In PMODE/W's implementation of this function, the value returned in ES is
  equivalent to the 4G data selector returned in DS at startup.

) This function is always successful under PMODE/W.

------------------------------------------------------------------------------
--------------------------- 3 - DPMI 'C' Wrappers ----------------------------
------------------------------------------------------------------------------

3 - DPMI 'C' Wrappers

  The following 'C' wrappers are provided to allow C programmers to
easily create INT/IRQ and callback handlers in C.  I still think making
C handlers are very hard and should be avoided, but I created these
for die hard C programmers.

3.0 - Allocate INT/IRQ Wrapper
------------------------------

  Allocates a interrupt handler wrapper.  This wrapper will call your
C procedure from within the wrapper.  The wrapper will setup all segment
registers before calling your C procedure and once your C procedure returns
the wrapper will pop all registers back off the stack and do an 'IRETD'.

  dword _DPMI_wrapper_int(void (*cr)());

In:
  cr => offset of your C procedure

Out:
  if successful:
    dword = offset of the wrapper

  if failed:
    dword = 0xfffffff

Notes:
) The returned value should be placed in a pmPROCstruct and used with
  _DPMI_setpmint()
) Use free() to release the allocated wrapper after you don't need it

3.1 - Allocate RETF Callback Wrapper
------------------------------------

  Allocates a callback handler wrapper.  This wrapper will call your
C procedure from within the wrapper.  The wrapper will setup all segment
registers before calling your C procedure and once your C procedure returns
the wrapper will pop all registers back off the stack and simulate
an RETF in the RMODE callstruct and do an 'IRETD'.

  dword _DPMI_wrapper_cb_retf(void (*cr)());

In:
  cr => offset of your C procedure

Out:
  if successful:
    dword = offset of the wrapper

  if failed:
    dword = 0xfffffff

Notes:
) The returned value should be placed in a pmPROCstruct and used with
  the _DPMI_callback_alloc() function
) Use free() to release the allocated wrapper after you don't need it

3.2 - Allocate IRET Callback Wrapper
------------------------------------

  Allocates a callback handler wrapper.  This wrapper will call your
C procedure from within the wrapper.  The wrapper will setup all segment
registers before calling your C procedure and once your C procedure returns
the wrapper will pop all registers back off the stack and simulate
an IRET in the RMODE callstruct and do an 'IRETD'.

  dword _DPMI_wrapper_cb_iret(void (*cr)());

In:
  cr => offset of your C procedure

Out:
  if successful:
    dword = offset of the wrapper

  if failed:
    dword = 0xfffffff

Notes:
) The returned value should be placed in a pmPROCstruct and used with
  the _DPMI_callback_alloc() function
) Use free() to release the allocated wrapper after you don't need it

------------------------------------------------------------------------------
-------------------- 4 - Callback Termination (ASM only) ---------------------
------------------------------------------------------------------------------

4.0 - Terminate Callback Routine (RETF stack frame) (ASM only)
--------------------------------------------------------------

  Terminates a callback routine with RETF stack frame.

  _DPMI_callback_retf : near

Notes:
) This rountine must be JMPed to
) This should be called by ASM programmers only
) You must call this function from within a callback rountine
) DS:ESI and ES:EDI must be preserved
) This function does not return (oviously)
) This function is used by wrappers allocated by _DPMI_wrapper_cb_retf() 

4.1 - Terminate Callback Routine (IRET stack frame) (ASM only)
--------------------------------------------------------------

  Terminates a callback routine with IRET stack frame.

  _DPMI_callback_iret : near

Notes:
) This rountine must be JMPed to
) This should be called by ASM programmers only
) You must call this function from within a callback rountine
) DS:ESI and ES:EDI must be preserved
) This function does not return (oviously)
) This function is used by wrappers allocated by _DPMI_wrapper_cb_iret() 

------------------------------------------------------------------------------
------------------------ End of QLIB    Documentation ------------------------
------------------------------------------------------------------------------

