[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]

    {
    JD3GTRCW.TRANSCOM@transcom.safb.af.mil (CONROY WILLIAM F)

    I have seen numerous requests for XMS routines.  Here are some I have
    written for a programming effort I headed.
    Feel free to use in any way fit.
    }

    {$O+,F+}
    UNIT XMSUnit;
    {    Programmer:  Major William F. Conroy III                             }
    {    Last Mod:    3/12/93                                                 }
    {    Touched:     File date set to coorespond to baseline date            }
    {                 for Computer Aided Aircrew Scheduling System            }
    {                                                                         }
    { This unit is written to give access to the XMS memory Specification for }
    { the IBM PC.  Do not alter this unit without an excellent understanding  }
    { of the PC internal architecture, the Extended Memory Specification(XMS) }
    { and the Borland Inline Assembler.  For a much more in depth discussion  }
    { of the XMS memory standard and how to implement it on a PC class
      computer }
    { Refer to "Extending Dos" by Ray Duncan, Published by Addison Wesley     }

    INTERFACE

    TYPE
      PHandlePtrArray = ^THandlePtrArray;
      THandlePtrArray = ARRAY [1..10]OF WORD;
      {  This type definition is used by the graphics system as a way   }
      {  to dynamically allocate space to hold the handles required to  }
      {  access the extended memory.                                    }

      PXMSParamBlock  = ^TXMSParamBlock;
      TXMSParamBlock  = RECORD
        LengthOfBlock   : LONGINT;   { Size of block to move }
        SourceEMBHandle : WORD;
        { 0 if source is in conventional memory,       }
        { handle returned by AllocateEMB otherwise     }
        SourceOffset    : LONGINT;
        { if SourceEMBHandle= 0 SourceOffset contains  }
        { a far pointer in Intel standard format else  }
        { SourceOffset indicates offset from the base  }
        { of the block.                                }
        DestEMBHandle   : WORD;
        { 0 if source is in conventional memory,       }
        { handle returned by AllocateEMB otherwise     }
        DestOffset      : LONGINT;
        { if DestEMBHandle= 0 DestOffset contains      }
        { a far pointer in Intel standard format else  }
        { DestOffset indicates offset from the base    }
        { of the block.                                }
      END;
      { This type definition is used by the XMM memory manager for      }
      { block memory moves. As required by the xms specification.       }

    VAR
      XMSExists : BOOLEAN;

      { Function AllocateEMB allocates an Extended Memory Block in Extended }
      { memory.  It requests the block via the Extended Memory Manager(XMM) }
      { It returns True if it was successful False otherwise.  If true, if  }
      { EMB_Handle will contain the Extended Memory Block Handle.  If       }
      {returning false, the errorcode is in the ErrorCode parameter.        }
    FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested, ErrorCode : WORD) : BOOLEAN;

      { Function FreeEMB releases an Extended Memory Block in Extended Memory }
      { allocated by the AllocateEMB function call.  It requests the XMM      }
      { remove the block.  It returns True if it was successful False         }
      { otherwise.  If true, if block was released correctly.  If returning   }
      { false, the errorcode is in the ErrorCode parameter.                   }
    FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN;

      { Function MoveEMB allows memory tranfers between conventional and XMS  }
      { Memory.  This function requires a filled in TXMSParamBlock record.    }
      { It returns True if it was successful False otherwise.  If true, the   }
      { memory block was successfully moved.  If returning false, the         }
      { errorcode is in the ErrorCode parameter.                   }
    FUNCTION MoveEMB(PParamBlock : PXMSParamBlock; VAR ErrorCode : WORD) : BOOLEAN;

    IMPLEMENTATION

    VAR
      XMMAddress        : POINTER;
      XMS_Version       : WORD;
      XMM_DriverVersion : WORD;
      HMA_Exists        : BOOLEAN;
      LastErrorCode     : WORD;

    {---------------------------------------------------------------------------}
    {                                                                         }
    {                             Local Procedure                             }
    {                            function XMSPresent                          }
    {                                                                         }
    {  This function return true if there is an Extended memory manager present }
    {  in the system capable of supporting our XMS requests.  It uses a DOS   }
    {  multiplexing interrupt request to determine if the driver signiture is }
    {  present in the system.  This is the Microsoft recomended method of     }
    {  determining the presence of this driver.                               }
    {                                                                         }
    {---------------------------------------------------------------------------}

    FUNCTION XMSPresent : BOOLEAN; ASSEMBLER;

    ASM
      MOV AX, 4300h                  { MultiPlexing interrupt request number  }
      INT 2fh                       { Dos Multiplexing Interrupt             }
      CMP AL, 80h                    { was the signature byte returned in AL  }
      JZ  @1                         { yes?, jump to @1                       }
      MOV AX, 00h                    { set false for return                   }
      JMP @2                        { unconditional jump to end of function  }
     @1:
      MOV AX, 01h                    { set True for return then fall thru to  }
                                    { exit.                                  }
     @2:
    END;

    {------------------------------------------------------------------------- --}
    {                                                                          }
    {                            Local Procedure                               }
    {                      function ReturnDriverAddress                        }
    {                                                                          }
    {  This function return true if it could determine the device driver entry  }
    {  point.  This information is required to call any XMS functions. It uses  }
    {  a DOS multiplexing interrupt request to get this address. This is the }
    {  Microsoft recomended method of getting the base address of this driver.  }
    {  This address is required to setup an indirect call to the driver by the  }
    {  XMS functions.                                                           }
    {                                                                           }
    {---------------------------------------------------------------------------}
    FUNCTION ReturnDriverAddress : POINTER; ASSEMBLER;
      {  This function returns the address for the XMM memory manager  }
      {  This value is required to later call the driver for XMS calls }

    ASM
      MOV AX, 4310h                  { MultiPlexing interrupt request number }
      INT 2fh                       { Dos Multiplexing Interrupt            }
                                    { Set Registers up for Return of Pointer }
      MOV AX, BX                     { Set Offset Value                      }
      MOV DX, ES                     { Set Segment Value                     }
    END;

    {-------------------------------------------------------------------------}
    {                                                                         }
    {                               Local Procedure                           }
    {                            function GetXMSVersion                       }
    {                                                                         }
    {-------------------------------------------------------------------------}
    FUNCTION GetXMSVersion(VAR XMS_Version, XMM_DriverVersion : WORD;
                           VAR HMA_Exists : BOOLEAN;
                           VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

      { This function loads the version numbers into the unit global }
      { variables. The information is coded in binary Coded Decimal. }

    ASM
      XOR  AX, AX                     { set ax to zero                        }
      CALL XMMAddress               { indirect call to XMM driver           }
      CMP  AX, 00h                    { error set ?                           }
      JZ   @1                         { Jump error finish                     }

      LES  DI, XMS_Version            { Load XMS_Version Address into es:di   }
      MOV  ES:[DI],AX                { Load variable indirect                }

      LES  DI, XMM_DriverVersion      { Load XMM_DriverVrsn Address in es:di  }
      MOV  ES:[DI],BX                { Load variable Indirect                }

      LES  DI, HMA_Exists             { Load HMA_Exists Address in es:di      }
      MOV  ES:[DI],DX                { Load variable Indirect                }

      LES  DI,ErrorCode              { Load ErrorCode Address into es:di     }
      MOV  WORD PTR ES:[DI],00h      { Clear Error Code                      }
      MOV  AX, 01h                    { set function return to true           }
      JMP  @2                        { Jump to finish                        }

     @1:
      LES DI, ErrorCode              { Load error code address in es:di      }
      MOV WORD PTR ES:[DI],00h      { copy 0  into ErrorCode                }
     @2:
    END;

    {-------------------------------------------------------------------------}
    {                                                                         }
    {                             Exported Procedure                          }
    {                            function AllocateEMB                         }
    {                                                                         }
    {                                                                         }
    {    Function AllocateEMB allocates an Extended Memory Block in Extended  }
    {    memory.  It requests the block via the Extended Memory Manager(XMM)  }
    {    It returns True if it was successful False otherwise.  If true, if   }
    {    EMB_Handle will contain the Extended Memory Block Handle.  If        }
    {    returning false, the errorcode is in the ErrorCode parameter.        }
    {                                                                         }
    {-------------------------------------------------------------------------}
    FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested,
                             ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

    ASM
      MOV  AH, 09h                    { set ax for Allocate EMB call       }
      LES  DI, ParRequested           { load ParRequested address in es:di }
      MOV  DX, ES:[DI]                { copy parRequested value in DX      }
      CALL XMMAddress               { indirect call to XMM driver        }
      CMP  AX, 00h                    { error set ?                        }
      JZ   @1                         { Jump error finish                  }
      LES  DI, EMB_Handle             { load EMB_Handle in es:di           }
      MOV  ES:[DI],DX                { copy DX into EMB_Handle            }
      MOV  AX, 01h                    { Return True                        }
      LES  DI, ErrorCode              { Load error code address in es:di   }
      MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode             }
      JMP  @2                        { unconditional jump to finish       }
      { Error Finish                       }
     @1:
      LES  DI, ErrorCode              { load ErrorCode in es:di            }
      MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode             }
     @2:
    END;

    {-------------------------------------------------------------------------}
    {                                                                         }
    {                           Exported Procedure                            }
    {                            function FreeEMB                             }
    {                                                                         }
    {  Function FreeEMB releases an Extended Memory Block in Extended Memory  }
    {  allocated by the AllocateEMB function call.  It requests the XMM       }
    {  remove the block.  It returns True if it was successful False          }
    {  otherwise.  If true, if block was released correctly.  If returning    }
    {  false, the errorcode is in the ErrorCode parameter.                    }
    {                                                                         }
    {-------------------------------------------------------------------------}
    FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

    ASM
      XOR  AX, AX                     { clear AX to zero                 }
      MOV  AH, 0Ah                    { set ax for Free EMB call         }
      LES  DI, EMB_Handle             { load EMB_Handle address in es:di }
      MOV  DX, ES:[DI]                { load EMB_Handle value in DX      }
      CALL XMMAddress               { indirect call to XMM driver      }
      CMP  AX, 00h                    { error set ?                      }
      JZ   @1                         { Jump error finish                }
      MOV  AX, 01H                    { Set True                         }
      LES  DI, ErrorCode              { Load error code address in es:di }
      MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode           }
      JMP  @2                        { unconditional jump to finish     }
                                    { Error Finish                     }
     @1:
      LES  DI, ErrorCode              { load ErrorCode in es:di          }
      MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode           }
     @2:
    END;

    {-------------------------------------------------------------------------}
    {                                                                         }
    {                           Exported Procedure                            }
    {                            function MoveEMB                             }
    {                                                                         }
    {  Function MoveEMB allows memory tranfers between conventional and XMS   }
    {  Memory.  This function requires a filled in TXMSParamBlock record.     }
    {  It returns True if it was successful False otherwise.  If true, the    }
    {  memory block was successfully moved.  If returning false, the          }
    {  errorcode is in the ErrorCode parameter.                               }
    {                                                                         }
    {-------------------------------------------------------------------------}
    FUNCTION MoveEMB(PParamBlock : PXMSParamBlock;
                     VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

    ASM
      MOV  AX, DS                     { move DS to AX register                }
      MOV  ES, AX                     { move AX to ES register                }
      MOV  AH, 0Bh                    { set ax for Move EMB call              }
      PUSH DS                       { push DS to Stack                      }
      LDS  SI, PParamBlock            { load PParamBlock Address to ds:si     }
      MOV  DI, OFFSET XMMAddress      { move XMMAddress offset to di          }
      CALL DWORD PTR ES:[DI]        { indirect call to XMMdriver via es:di  }
      POP  DS                        { save TP's data segment                }
      CMP  AX, 00h                    { error set ?                           }
      JZ   @1                         { Jump error finish                     }
      MOV  AX, 01H                    { Set True                              }
      LES  DI, ErrorCode              { Load error code address in es:di      }
      MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode                }
      JMP  @2                        { unconditional jump to finish          }
                                    { Error Finish                          }
     @1:
      LES  DI, ErrorCode              { load ErrorCode in es:di               }
      MOV  WORD PTR ES:[DI],AX       { Clear ErrorCode prior to load         }
      MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode                }
      MOV  AX, 01h                    { Return False                          }
     @2:
    END;

    BEGIN
      XMSExists := XMSPresent;
      IF XMSExists THEN
      BEGIN
        XMMAddress := ReturnDriverAddress;
        GetXMSVersion(XMS_Version, XMM_DriverVersion, HMA_Exists, LastErrorCode);
      END;
    END.

[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]