The associated file (LIMEMS41.DOC) is a complete transcription of
          the Lotus/Intel/Microsoft (LIM) Expanded Memory Specification
          (EMS) Version 4.0, updated October 1987.  It can be printed by
          "COPY LIMEMS41.DOC PRN:"

          I created this transcription because of the difficulty I origin-
          ally had finding a copy of the document, because of the number of
          people who have subsequently expressed an interest in having
          access to a machine-readable copy of the specification, and,
          finally, because of the annoying number of typographical errors
          contained in the original and updated documents.

          This transcription is not an exact letter-for-letter duplicate of
          the original document.  Some minor changes were necessitated by
          the simple fact that the document's proportionally-spaced, multi-
          fonted typography and line drawings did not lend themselves to
          the generic fixed-spacing, single-fonted, non-graphical ASCII
          transcription I wanted to produce for general dissemination.

          Other minor changes were made to correct obvious typographical
          and grammatical errors, or to simply improve the visual aes-
          thetics of the presented material.

          In one area, however, I simply trashed their original material
          and substituted my own.  This area is the Index.  The original
          document contains an Index that is little more than a reformatt-
          ing of the Table of Contents.  As anyone who has ever indexed a
          large document knows, it is very difficult to produce an Index
          that is both complete AND easy to use.  I didn't have time to
          produce one that was both, so I aimed for the former.  In fact,
          the Index I have provided is more of an alphabetical listing of
          key words and phrases and the pages where they are referenced,
          than it is a more typical Index with its multi-level headings and
          subheadings.

          You should be able obtain a printed, 3-hole-punched, 5.5 x 8.5"
          copy of the original (and uncorrected) document directly from
          Intel by calling their "Information Department" at 1-800-538-3373
          and asking for a copy of the "LIM EMS 4.0 Developer's Kit."  It
          is available free of charge and mine arrived in about two weeks. 
          (European availability, however, is reported to be from poor to
          non-existent.)

          It is my intent to provide this transcription as a public
          service.  I am, therefore, releasing it into the public domain. 
          The original document has also been released into the public
          domain by Lotus, Intel, and Microsoft, though it remains their
          copyrighted property (I'm not quite sure how they manage to do
          that).

          I have tried as best I can to provide an accurate and corrected
          transcription of the original document.  It is inevitable,
          however, that some typographical errors have slipped through in
          spite of my hours of bleary-eyed proof reading.  For these errors
          I apologize and plead simple human frailty.

               THIS TRANSCRIPTION IS PROVIDED WITHOUT ANY GUARANTEES
               OR WARRANTIES OF ANY KIND, AND I ASSUME ABSOLUTELY NO
               LIABILITY FOR ITS ACCURACY, CONTENT, OR SUBSEQUENT USE.

          Dick Flanagan, W6OLD, Ben Lomond, California        November 1987











                           LOTUS(R)/INTEL(R)/MICROSOFT(R)

                          EXPANDED MEMORY SPECIFICATION [1]












                                     Version 4.0
                                     300275-005
                                    October, 1987












          Copyright (C) 1987

          Lotus Development Corporation
          55 Cambridge Parkway
          Cambridge, MA  02142

          Intel Corporation
          5200 NE Elam Young Parkway
          Hillsboro, OR  97124

          Microsoft Corporation
          16011 NE 35th Way
          Box 97017
          Redmond, WA  98073


               [1] Transcribed into machine-readable form by Dick Flanagan,
          Ben Lomond, California.  This transcription is released into the
          public domain without warranty or assumption of liability.





               This specification was jointly developed by Lotus Develop-
               ment Corporation, Intel Corporation, and Microsoft Corpora-
               tion.  Although it has been released into the public domain
               and is not confidential or proprietary, the specification is
               still the copyright and property of Lotus Development
               Corporation, Intel Corporation, and Microsoft Corporation.


          DISCLAIMER OF WARRANTY

               LOTUS DEVELOPMENT CORPORATION, INTEL CORPORATION, AND MICRO-
               SOFT CORPORATION EXCLUDE ANY AND ALL IMPLIED WARRANTIES,
               INCLUDING WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
               PARTICULAR PURPOSE.  NEITHER LOTUS NOR INTEL NOR MICROSOFT
               MAKE ANY WARRANTY OF REPRESENTATION, EITHER EXPRESS OR
               IMPLIED, WITH RESPECT TO THIS SPECIFICATION, ITS QUALITY,
               PERFORMANCE, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
               PURPOSE.  NEITHER LOTUS NOR INTEL NOR MICROSOFT SHALL HAVE
               ANY LIABILITY FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
               DAMAGES ARISING OUT OF OR RESULTING FROM THE USE OR MODIF-
               ICATION OF THIS SPECIFICATION.



          This specification uses the following trademarks:

          Intel is a trademark of Intel Corporation
          Lotus is a trademark of Lotus Development Corporation
          Microsoft is a trademark of Microsoft Corporation
























                                                                         ii





          CONTENTS



          Chapter 1
          INTRODUCTION
            What is Expanded Memory? . . . . . . . . . . . . . . . . .    1
            How Expanded Memory Works  . . . . . . . . . . . . . . . .    1

          Chapter 2
          WRITING PROGRAMS THAT USE EXPANDED MEMORY
            What Every Program Must Do . . . . . . . . . . . . . . . .    4
            Advanced Programming . . . . . . . . . . . . . . . . . . .    5
              Saving The State of Mapping Hardware . . . . . . . . . .    6
              Retrieving Handle and Page Counts  . . . . . . . . . . .    6
              Mapping and Unmapping Multiple Pages . . . . . . . . . .    6
              Reallocating Pages . . . . . . . . . . . . . . . . . . .    6
              Using Handles and Assigning Names to Handles . . . . . .    6
              Using Handle Attributes  . . . . . . . . . . . . . . . .    7
              Altering Page Maps and Jumping/Calling . . . . . . . . .    7
              Moving or Exchanging Memory Regions  . . . . . . . . . .    7
              Getting the Amount of Mappable Memory  . . . . . . . . .    8
              Operating System Functions . . . . . . . . . . . . . . .    8
            Programming Guidelines . . . . . . . . . . . . . . . . . .   12
            Examples . . . . . . . . . . . . . . . . . . . . . . . . .   14
              Example 1  . . . . . . . . . . . . . . . . . . . . . . .   14
              Example 2  . . . . . . . . . . . . . . . . . . . . . . .   19
              Example 3  . . . . . . . . . . . . . . . . . . . . . . .   30
              Example 4  . . . . . . . . . . . . . . . . . . . . . . .   32

          Chapter 3
          EMM FUNCTIONS
            Function 1. Get Status . . . . . . . . . . . . . . . . . .   37
            Function 2. Get Page Frame Address . . . . . . . . . . . .   38
            Function 3. Get Unallocated Page Count . . . . . . . . . .   40
            Function 4. Allocate Pages . . . . . . . . . . . . . . . .   42
            Function 5. Map/Unmap Handle Pages . . . . . . . . . . . .   46
            Function 6. Deallocate Pages . . . . . . . . . . . . . . .   49
            Function 7. Get Version  . . . . . . . . . . . . . . . . .   51
            Function 8. Save Page Map  . . . . . . . . . . . . . . . .   53
            Function 9. Restore Page Map . . . . . . . . . . . . . . .   55
            Function 10. Reserved  . . . . . . . . . . . . . . . . . .   57
            Function 11. Reserved  . . . . . . . . . . . . . . . . . .   58
            Function 12. Get Handle Count  . . . . . . . . . . . . . .   59
            Function 13. Get Handle Pages  . . . . . . . . . . . . . .   61
            Function 14. Get All Handle Pages  . . . . . . . . . . . .   63
            Function 15. Get/Set Page Map  . . . . . . . . . . . . . .   65
              Get Page Map subfunction . . . . . . . . . . . . . . . .   65
              Set Page Map subfunction . . . . . . . . . . . . . . . .   67
              Get & Set Page Map subfunction . . . . . . . . . . . . .   69
              Get Size of Page Map Save Array subfunction  . . . . . .   71


                                                                        iii





            Function 16. Get/Set Partial Page Map  . . . . . . . . . .   73
              Get Partial Page Map subfunction . . . . . . . . . . . .   73
              Set Partial Page Map subfunction . . . . . . . . . . . .   76
              Get Size of Partial Page Map Save Array subfunction  . .   78
            Function 17. Map/Unmap Multiple Handle Pages . . . . . . .   80
              Mapping Multiple Pages . . . . . . . . . . . . . . . . .   80
              Unmapping Multiple Pages . . . . . . . . . . . . . . . .   80
              Mapping and Unmapping Multiple Pages Simultaneously  . .   80
              Alternate Mapping and Unmapping Methods  . . . . . . . .   81
              Logical Page/Physical Page Method  . .OF THE EXPANDED MEMORY MANAGER
            Which method should your program use?  . . . . . . . . . .  199
            The "open handle" technique  . . . . . . . . . . . . . . .  199
            The "get interrupt vector" technique . . . . . . . . . . .  204

          Appendix C
          EXPANDED MEMORY MANAGER IMPLEMENTATION GUIDELINES
            The amount of expanded memory supported  . . . . . . . . .  206
            The number of handles supported  . . . . . . . . . . . . .  206
            Handle Numbering . . . . . . . . . . . . . . . . . . . . .  206
            New handle type:  Handles versus Raw Handles . . . . . . .  206
            The system Raw Handle (Raw Handle = 0000h) . . . . . . . .  207
            Terminate and Stay Resident (TSR) Program Cooperation  . .  208
            Accelerator Cards  . . . . . . . . . . . . . . . . . . . .  208

          Appendix D
          OPERATING SYSTEM/ENVIRONMENT USE OF FUNCTION 28
            Examples . . . . . . . . . . . . . . . . . . . . . . . . .  209
              Example 1  . . . . . . . . . . . . . . . . . . . . . . .  209
              Example 2  . . . . . . . . . . . . . . . . . . . . . . .  210
              Example 3  . . . . . . . . . . . . . . . . . . . . . . .  211

          GLOSSARY

          INDEX















                                                                          v





          Chapter 1
          INTRODUCTION


               Because even the maximum amount (640K bytes) of conventional
               memory isn't always enough for large application programs,
               Lotus Development Corporation, Intel Corporation, and Micro-
               soft Corporation created the Lotus/Intel/Microsoft (LIM)
               Expanded Memory Specification.

               The LIM Expanded Memory Specification defines the software
               interface between the Expanded Memory Manager (EMM) -- a
               device driver that controls and manages expanded memory --
               and application programs that use expanded memory.


          What is Expanded Memory?

               Expanded memory is memory beyond DOS's 640K-byte limit.  The
               LIM specification supports up to 32M bytes of expanded
               memory.  Because the 8086, 8088, and 80286 (in real mode)
               microprocessors can physically address only 1M bytes of
               memory, they access expanded memory through a window in
               their physical address range.  The next section explains how
               this is done.


          How Expanded Memory Works

               Expanded memory is divided into segments called logical
               pages.  These pages are typically 16K bytes of memory.  Your
               computer accesses logical pages through a physical block of
               memory called a page frame.  The page frame contains
               multiple physical pages, pages that the microprocessor can
               address directly.  Physical pages are also typically 16K
               bytes of memory.

               This page frame serves as a window into expanded memory. 
               Just as your computer screen is a window into a large
               spreadsheet, so the page frame is a window into expanded
               memory.

               A logical page of expanded memory can be mapped into (made
               to appear in) any one of the physical pages in the page
               frame.  Thus, a read or write to the physical page actually
               becomes a read or write to the associated logical page.  One
               logical page can be mapped into the page frame for each
               physical page.

               Figure 1-1 shows the relationship among the page frame,
               physical pages, and logical pages.


          Introduction                                                    1





                                                       32M +--------------+
                                                          /|              |
                                                           |              |
                                                     /     |              |
                                                           |              |
                                                /          |              |
                                                           |              |
                                           /               |              |
                                                           |   Expanded   |
                                      /                    |    Memory    |
          1024K +--------------+                           |              |
                | / / / / / /  | /                         |              |
           960K +--------------+                           |              |
                |  Page Frame  |                           |              |
                |              |                           |              |
                | 12 16K-Byte  |                           |              |
                |   Physical   |                           |              |
                |    Pages     |                           |              |
           768K +--------------+                           | Divided into |
                | / / / / / /  | \                         |   logical    |
           640K +--------------+                           |    pages     |
                |              |   \                       |              |
                |              |                           |              |
                |              |     \                     |              |
                |              |                           |              |
                | 24 16K-Byte  |       \                   |              |
                |   Physical   |                           |              |
                |    Pages*    |         \                 |              |
                |              |                           |              |
                |              |           \               |              |
                |              |                           |              |
                |              |             \             |              |
           256K +--------------+                           |              |
                |              |               \           |              |
                | / / / / / /  |                           |              |
                |              |                 \         |              |
                | / / / / / /  |                           |              |
                |              |                   \       |              |
                | / / / / / /  |                           |              |
                |              |                     \     |              |
              0 +--------------+                           |              |
                                                       \   |              |
                                                           |              |
          *Intended for operating                        \ |              |
           system/environment use only                   0 +--------------+



          Figure 1-1.  Expanded Memory




          Introduction                                                    2





               The page frame is located above 640K bytes.  Normally, only
               video adapters, network cards, and similar devices exist
               between 640K and 1024K.

               This specification also defines methods for operating
               systems and environments to access expanded memory through
               physical pages below 640K bytes.  These methods are intended
               for operating system/environment developers only.













































          Introduction                                                    3





          Chapter 2
          WRITING PROGRAMS THAT USE EXPANDED MEMORY


               This chapter describes what every program must do to use
               expanded memory and describes more advanced techniques of
               using expanded memory.

               This chapter also lists programming guidelines you should
               follow when writing programs that use expanded memory and
               provides the listings of some example programs.


          What Every Program Must Do

               This section describes the steps every program must take to
               use expanded memory.

               In order to use expanded memory, applications must perform
               these steps in the following order:

               1.  Determine if EMM is installed.

               2.  Determine if enough expanded memory pages exist for your
                   application.  (Function 3)

               3.  Allocate expanded memory pages.  (Function 4, 18, or 27)

               4.  Get the page frame base address.  (Function 2)

               5.  Map in expanded memory pages.  (Function 5 or 17)

               6.  Read/write/execute data in expanded memory, just as if
                   it were conventional memory.

               7.  Return expanded memory pages to expand memory pool
                   before exiting.  (Function 6 or 18)

               Table 2-1 overviews the functions while Chapter 3 describes
               each of these functions in detail.  Example programs at the
               end of this chapter illustrate using expanded memory.












          Writing Programs That Use Expanded Memory                       4





          Table 2-1.  The Basic Functions
          ----------------------------------------------------------------

          Function                        Description

          ----------------------------------------------------------------

             1         The Get Status Function returns a status code
                       indicating whether the memory manager hardware is
                       working correctly.

             2         The Get Page Frame Address function returns the
                       address where the 64K-byte page frame is located.

             3         The Get Unallocated Page Count function returns the
                       number of unallocated pages (pages available to your
                       program) and the total number of pages in expanded
                       memory.

             4         The Allocate Pages function allocates the number of
                       pages requested and assigns a unique EMM handle to
                       these pages.

             5         The Map/Unmap Handle Page function maps a logical
                       page to a specific physical page anywhere in the
                       mappable regions of system memory.

             6         The Deallocate Pages deallocates the logical pages
                       currently allocated to an EMM handle.

             7         The Get Version function returns the version number
                       of the memory manager software.

          ----------------------------------------------------------------



          Advanced Programming

               In addition to the basic functions, the Lotus/Intel/Micro-
               soft Expanded Memory Specification provides several advanced
               functions which enhance the capabilities of software that
               uses expanded memory.

               The following sections describe the advanced programming
               capabilities and list the advanced EMM functions.


          Note............................................................
               Before using the advanced functions, programs should first
               call Function 7 (Get Version) to determine whether the
               installed version of EMM supports these functions.

          Writing Programs That Use Expanded Memory                       5





          Saving The State of Mapping Hardware

               Some software (such as interrupt service routines, device
               drivers, and resident software) must save the current state
               of the mapping hardware, switch mapping contexts, manipulate
               sections of expanded memory, and restore the original
               context of the memory mapping hardware.  Use Functions 8 and
               9 or 15 and 16 to save the state of the hardware.


          Retrieving Handle and Page Counts

               Some utility programs need to keep track of how expanded
               memory is being used; use Functions 12 through 14 to do
               this.


          Mapping and Unmapping Multiple Pages

               Mapping multiple pages reduces the overhead an application
               must perform during mapping.  Function 17 lets a program map
               (or unmap) multiple pages at one time.

               In addition, you can map pages using segment addresses
               instead of physical pages.  For example, if the page frame
               base address is set to D000, you can map to either physical
               page 0 or segment D000.  Function 25 (Get Mappable Physical
               Address Array) returns a cross reference between all
               expanded memory physical pages and their corresponding
               segment values.


          Reallocating Pages

               Reallocating pages (Function 18) lets applications dynami-
               cally allocate expanded memory pages without acquiring
               another handle or obtain a handle without allocating pages. 
               Reallocating pages is an efficient means for applications to
               obtain and release expanded memory pages.


          Using Handles and Assigning Names to Handles

               This specification lets you associate a name with a handle,
               so a family of applications can share information in
               expanded memory.  For example, a software package consisting
               of a word processor, spreadsheet, and print spooler can
               share the same data among the different applications.  The
               print spooler could use a handle name to reference data that
               either the spreadsheet or word processor put in expanded
               memory and could check for data in a particular handle
               name's expanded memory pages.

          Writing Programs That Use Expanded Memory                       6





               Use Function 20 (Set Handle Name subfunction) to assign a
               handle name to an EMM handle or Function 21 (Search for
               Named Handle subfunction) to obtain the EMM handle as-
               sociated with the handle name.  In addition, you can use
               Function 14 (Get Handle Pages) to determine the number of
               expanded memory pages allocated to an EMM handle.


          Using Handle Attributes

               In addition to naming a handle, you can use Function 19 to
               associate an attribute (volatile or non-volatile) with a
               handle name.  A non-volatile attribute enables expanded
               memory pages to preserve their data through a warmboot. 
               With a volatile attribute, the data is not preserved.  The
               default attribute for handles is volatile.

               Because using this function depends on the capabilities of
               the expanded memory hardware installed in the system, you
               should use the Get Attribute Capability subfunction before
               attempting to assign an attribute to a handle's pages.


          Altering Page Maps and Jumping/Calling

               You can use Functions 22 (Alter Page Map & Jump) and 23
               (Alter Page Map & Call) to map a new set of values into the
               map registers and transfer program control to a specified
               address within expanded memory.  These functions can be used
               to load and execute code in expanded memory.  An application
               using this feature can significantly reduce the amount of
               conventional memory it requires.  Programs can load needed
               modules into expanded memory at run time and use Functions
               22 and 23 to transfer control to these modules.

               Using expanded memory to store code can improve program
               execution in many ways.  For example, sometimes programs
               need to be divided into small overlays because of conven-
               tional memory size limitations.  Overlays targeted for
               expanded memory can be very large because LIM EMS 4.0
               supports up to 32M bytes of expanded memory.  This method of
               loading overlays improves overall system performance by
               conserving conventional memory and eliminating conventional
               memory allocation errors.


          Moving or Exchanging Memory Regions

               Using Function 24 (Move/Exchange Memory Region), you can
               easily move and exchange data between conventional and
               expanded memory.  Function 24 can manipulate up to one
               megabyte of data with one function call.  Although applica-

          Writing Programs That Use Expanded Memory                       7





               tions can perform this operation without this function,
               having the expanded memory manager do it reduces the amount
               of overhead for the application.

               In addition, this function checks for overlapping regions
               and performs all the necessary mapping, preserving the
               mapping context from before the exchange/move call.


          Getting the Amount of Mappable Memory

               Function 25 enables applications to determine the total
               amount of mappable memory the hardware/system currently
               supports.  Not all expanded memory boards supply the same
               number of physical pages (map registers).

               The Get Mappable Physical Address Array Entries subfunction
               returns the total number of physical pages the expanded
               memory hardware/system is capable of supporting.  The Get
               Mappable Physical Array subfunction returns a cross refer-
               ence between physical page numbers and the actual segment
               address for each of the physical pages.


          Operating System Functions

               In addition to the functions for application programs, this
               specification defines functions for operating systems/en-
               vironments.  These functions can be disabled at any time by
               the operating system/environment, so programs should not
               depend on their presence.  Applications that avoid this
               warning and use these functions run a great risk of being
               incompatible with other programs, including the operating
               system.



















          Writing Programs That Use Expanded Memory                       8





          Table 2-2.  The Advanced Functions
          ----------------------------------------------------------------

          Function                        Description

          ----------------------------------------------------------------

             8         The Save Page Map saves the contents of the page
                       mapping registers from all expanded memory boards in
                       an internal save area.

             9         The Restore Page Map function restores (from an
                       internal save area) the page mapping register
                       contents on the expanded memory boards for a
                       particular EMM handle.

             10        Reserved.

             11        Reserved.

             12        The Get Handle Count function returns the number of
                       open EMM handles in the system.

             13        The Get Handle Pages function returns the number of
                       pages allocated to a specific EMM handle.

             14        The Get All Handle Pages function returns an array
                       of the active EMM handles and the number of pages
                       allocated to each one.

             15        The Get/Set Page Map subfunction saves or restores
                       the mapping context for all mappable memory regions
                       (conventional and expanded) in a destination array
                       which the application supplies.

             16        The Get/Set Partial Page Map subfunction provides a
                       mechanism for saving a partial mapping context for
                       specific mappable memory regions in a system.

             17        The Map/Unmap Multiple Handle Pages function can, in
                       a single invocation, map (or unmap) logical pages
                       into as many physical pages as the system supports.

             18        The Reallocate Pages function can increase or
                       decrease the amount of expanded memory allocated to
                       a handle.

             19        The Get/Set Handle Attribute function allows an
                       application program to determine and set the
                       attribute associated with a handle.



          Writing Programs That Use Expanded Memory                       9





          Table 2-2.  The Advanced Functions (continued)
          ----------------------------------------------------------------

          Function                        Description

          ----------------------------------------------------------------

             20        The Get/Set Handle Name function gets the eight
                       character name currently assigned to a handle and
                       can assign an eight character name to a handle.

             21        The Get Handle Directory function returns informa-
                       tion about active handles and the names assigned to
                       each.

             22        The Alter Page Map & Jump function alters the memory
                       mapping context and transfers control to the
                       specified address.

             23        The Alter Page Map & Call function alters the speci-
                       fied mapping context and transfers control to the
                       specified address.  A return can then restore the
                       context and return control to the caller.

             24        The Move/Exchange Memory Region function copies or
                       exchanges a region of memory from conventional to
                       conventional memory, conventional to expanded
                       memory, expanded to conventional memory, or expanded
                       to expanded memory.

             25        The Get Mappable Physical Address Array function
                       returns an array containing the segment address and
                       physical page number for each mappable physical page
                       in a system.

             26        The Get Expanded Memory Hardware Information
                       function returns an array containing the hardware
                       capabilities of the expanded memory system.

             27        The Allocate Standard/Raw Pages function allocates
                       the number of standard or non-standard size pages
                       that the operating system requests and assigns a
                       unique EMM handle to these pages.

             28        The Alternate Map Register Set function enables an
                       application to simulate alternate sets of hardware
                       mapping registers.

             29        The Prepare Expanded Memory Hardware for Warm Boot
                       function prepares the expanded memory hardware for
                       an "impending" warm boot.


          Writing Programs That Use Expanded Memory                      10





          Table 2-2.  The Advanced Functions (continued)
          ----------------------------------------------------------------

          Function                        Description

          ----------------------------------------------------------------

             30        The Enable/Disable OS/E function enables operating
                       systems developers to enable and disable functions
                       designed for operating system use.

          ----------------------------------------------------------------









































          Writing Programs That Use Expanded Memory                      11





          Programming Guidelines

               The following section contains guidelines for programmers
               writing applications that use EMM.

               o   Do not put a program's stack in expanded memory.

               o   Do not replace interrupt 67h.  This is the interrupt
                   vector the EMM uses.  Replacing interrupt 67h could
                   result in disabling the Expanded Memory Manager.

               o   Do not map into conventional memory address space your
                   application doesn't own.  Applications that use the EMM
                   to swap into conventional memory space, must first
                   allocate this space from the operating system.  If the
                   operating system is not aware that a region of memory it
                   manages is in use, it will think it is available.  This
                   could have disastrous results.  EMM should not be used
                   to "allocate" conventional memory.  DOS is the proper
                   manager of conventional memory space.  EMM should only
                   be used to swap data in conventional memory space
                   previously allocated from DOS.

               o   Applications that plan on using data aliasing in
                   expanded memory must check for the presence of expanded
                   memory hardware.  Data aliasing occurs when mapping one
                   logical page into two or more mappable segments.  This
                   makes one 16K-byte expanded memory page appear to be in
                   more than one 16K-byte memory address space.  Data
                   aliasing is legal and sometimes useful for applications.

                   Software-only expanded memory emulators cannot perform
                   data aliasing.  A simple way to distinguish software
                   emulators from actual expanded memory hardware is to
                   attempt data aliasing and check the results.  For
                   example, map one logical page into four physical pages. 
                   Write to physical page 0.  Read physical pages 1-3 to
                   see if the data is there as well.  If the data appears
                   in all four physical pages, then expanded memory
                   hardware is installed in the system, and data aliasing
                   is supported.

               o   Applications should always return expanded memory pages
                   to the expanded memory manager upon termination.  These
                   pages will be made available for other applications.  If
                   unneeded pages are not returned to the expanded memory
                   manager, the system could "run out" of expanded memory
                   pages or expanded memory handles.

               o   Terminate and stay resident programs (TSR's) should
                   ALWAYS save the state of the map registers before
                   changing them.  Since TSR's may interrupt other programs

          Writing Programs That Use Expanded Memory                      12





                   which may be using expanded memory, they must not change
                   the state of the page mapping registers without first
                   saving them.  Before exiting, TSR's must restore the
                   state of the map registers.

                   The following sections describe the three ways to save
                   and restore the state of the map registers.

                   1.  Save Page Map and Restore Page Map (Functions 8 and
                       9).  This is the simplest of the three methods.  The
                       EMM saves the map register contents in its own data
                       structures -- the application does not need to
                       provide extra storage locations for the mapping
                       context.  The last mapping context to be saved,
                       under a particular handle, will be restored when a
                       call to Restore Page Map is issued with the same
                       handle.  This method is limited to one mapping
                       context for each handle and saves the context for
                       only LIM standard 64K-byte page frames.

                   2.  Get/Set Page Map (Function 15).  This method
                       requires the application to allocate space for the
                       storage array.  The EMM saves the mapping context in
                       an array whose address is passed to the EMM.  When
                       restoring the mapping context with this method, an
                       application passes the address of an array which
                       contains a previously stored mapping context.

                       This method is preferable if an application needs to
                       do more than one save before a restore.  It provides
                       a mechanism for switching between more than one
                       mapping context.

                   3.  Get/Set Partial Page Map (Function 16).  This method
                       provides a way for saving a partial mapping context. 
                       It should be used when the application does not need
                       to save the context of all mappable memory.  This
                       function also requires that the storage array be
                       part of the application's data.

               o   All functions using pointers to data structures must
                   have those data structures in memory which will not be
                   mapped out.  Functions 22 and 23 (Alter Map & Call and
                   Alter Map & Jump) are the only exceptions.









          Writing Programs That Use Expanded Memory                      13





          Examples

               This section lists four example programs that demonstrate
               the use of expanded memory.


          Example 1

               This program was written using the Microsoft C compiler
               Version 3.0.  EMM function calls are made with the int86
               function found in the dos.h library.  To create an ex-
               ecutable program use the following compile command line:

                         msc /Gs /Oat /Ml program,,program;

          #include 
          #include 

          #define EMM_INT                 0x67  /* EMM interrupt number */
          #define GET_PAGE_FRAME          0x41  /* EMM get page frame */
                                                /* function number */
          #define GET_UNALLOC_PAGE_COUNT  0x42  /* EMM get unallocated */
                                                /* page count */
                                                /* function number */
          #define ALLOCATE_PAGES          0x43  /* EMM allocate pages */
                                                /* function number */
          #define MAP_PAGES               0x44  /* EMM map pages */
                                                /* function number */
          #define DEALLOCATE_PAGES        0x45  /* EMM deallocate pages */
                                                /* function number */
          #define DEVICE_NAME_LENGTH      8     /* length of a device */
                                                /* name string */
          #define TRUE                    1
          #define FALSE                   0

          union REGS input_regs, output_regs;
          struct SREGS segment_regs;
          int pf_addr;

          /*------------------------------------------------------------*/
          /* Routine to convert a segment:offset pair to a far ptr.     */
          /*------------------------------------------------------------*/
          char *build_ptr (segment, offset)

              unsigned int segment;
              unsigned int offset;
          {
              char *ptr;

              ptr = (char *)(((unsigned long)segment << 16) + offset);
              return (ptr);
          }

          Writing Programs That Use Expanded Memory                      14





          /*------------------------------------------------------------*/
          /* Function which determines whether EMM device driver        */
          /* is installed.                                              */
          /*------------------------------------------------------------*/
          char emm_installed()

          {
              char *EMM_device_name = "EMMXXXX0";
              char *int_67_device_name_ptr;

              /*--------------------------------------------------------*/
              /* AH = DOS get interrupt vector function.                */
              /*--------------------------------------------------------*/
              input_regs.h.ah = 0x35;

              /*--------------------------------------------------------*/
              /* AL = EMM interrupt vector number.                      */
              /*--------------------------------------------------------*/
              input_regs.h.al = EMM_INT;
              intdosx (&input_regs, &output_regs, &segment_regs);

              /*--------------------------------------------------------*/
              /* Upon return ES:0Ah points to location where            */
              /* device name should be.                                 */
              /*--------------------------------------------------------*/
              int_67_device_name_ptr = build_ptr (segment_regs.es, 0x0A);

              /*--------------------------------------------------------*/
              /* Compare memory with EMM device name.                   */
              /*--------------------------------------------------------*/
              if (memcmp (EMM_device_name, int_67_device_name_ptr,
                                             DEVICE_NAME_LENGTH) == 0)
                  return (TRUE);
              else
                  return (FALSE);
          }

          /*------------------------------------------------------------*/
          /* Function which determines if there are enough unallocated  */
          /* expanded memory pages for the application.                 */
          /*------------------------------------------------------------*/
          char enough_unallocated_pages (pages_needed)

              int pages_needed;
          {
              input_regs.h.ah = GET_UNALLOCATED_PAGE_COUNT;
              int86 (EMM_INT, &input_regs, &output_regs);
              if (output_regs.h.ah != 0 || pages_needed > output_regs.x.bx)
                  return (FALSE);
              else
                  return (TRUE);
          }

          Writing Programs That Use Expanded Memory                      15





          /*------------------------------------------------------------*/
          /* Function which allocates expanded memory pages and passes  */
          /* back to the main EMM handle.                               */
          /*------------------------------------------------------------*/
          char allocate_expanded_memory_pages (pages_needed,emm_handle_ptr)

              int pages_needed;
              unsigned int *emm_handle_ptr;
          {
              input_regs.h.ah = ALLOCATE_PAGES;
              input_regs.x.bx = pages_needed;
              int86 (EMM_INT, &input_regs, &output_regs);
              if (output_regs.h.ah == 0) {
                  *emm_handle_ptr = output_regs.x.dx;
                  return (TRUE);
              }
              else
                  return (FALSE);
          }

          /*------------------------------------------------------------*/
          /* Routine to map a logical page to a physical page.          */
          /*------------------------------------------------------------*/
          char map_expanded_memory_pages (emm_handle, physical_page,       
                                                             logical_page)
              unsigned int emm_handle;
              int physical_page;
              int logical_page;
          {
              input_regs.h.ah = MAP_PAGES;
              input_regs.h.al = physical_page;
              input_regs.x.bx = logical_page;
              input_regs.x.dx = emm_handle;
              int86 (EMM_INT, &input_regs, &output_regs);
              if (output_regs.h.ah == 0)
                  return (TRUE);
              else
                  return (FALSE);
          }














          Writing Programs That Use Expanded Memory                      16





          /*------------------------------------------------------------*/
          /* Routine which gets the page frame base address from EMM.   */
          /*------------------------------------------------------------*/
          char get_page_frame_address (pf_ptr)

              char **pf_ptr;
          {
              input_regs.h.ah = GET_PAGE_FRAME;
              int86 (EMM_INT, &input_regs, &output_regs);
              if (output_regs.h.ah != 0)       /* check EMM status */
                  return (FALSE);
              else
                 *pf_ptr = build_ptr (output_regs.x.bx, 0);
              return (TRUE);
          }

          /*------------------------------------------------------------*/
          /* Routine to release all expanded memory pages allocated     */
          /* by an EMM handle.                                          */
          /*------------------------------------------------------------*/

          char deallocate_expanded_memory_pages (emm_handle)

              unsigned int emm_handle;
          {
              input_regs.h.ah = DEALLOCATE_PAGES;
              input_regs.x.dx = emm_handle;
              int86 (EMM_INT, &input_regs, &output_regs);
              if (output_regs.h.ah == 0)
                  return (TRUE);
              else
                  return (FALSE);
          }

          main()

          {
              unsigned int emm_handle;
              char *pf_addr;
              int pages_needed;
              int physical_page;
              int logical_page;
              int index;

              /*--------------------------------------------------------*/
              /* Determine if EMM is installed.                         */
              /*--------------------------------------------------------*/
              if (!emm_installed())
                  exit(1);




          Writing Programs That Use Expanded Memory                      17





              /*--------------------------------------------------------*/
              /* Determine if enough expanded memory pages exist for    */
              /* application.                                           */
              /*--------------------------------------------------------*/
              pages_needed = 1;
              if (!enough_unallocated_pages (pages_needed))
                  exit(1);

              /*--------------------------------------------------------*/
              /* Allocate expanded memory pages.                        */
              /*--------------------------------------------------------*/
              if (!allocate_expanded_memory_pages (pages_needed,
                                                             &emm_handle))
                  exit(1);

              /*--------------------------------------------------------*/
              /* Map in the required pages.                             */
              /*--------------------------------------------------------*/
              physical_page = 0;
              logical_page = 0;
              if (!map_expanded_memory_pages (emm_handle, physical_page,
                                                            logical_page))
                  exit(1);

              /*--------------------------------------------------------*/
              /* Get expanded memory page frame address.                */
              /*--------------------------------------------------------*/
              if (!get_page_frame_address (&pf_addr))
                  exit(1);

              /*--------------------------------------------------------*/
              /* Write to expanded memory.                              */
              /*--------------------------------------------------------*/
              for (index = 0; index < 0x3fff; index++)
                  pf_addr[index] = index;

              /*--------------------------------------------------------*/
              /* Return expanded memory pages before exiting.           */
              /*--------------------------------------------------------*/
              if (!deallocate_expanded_memory_pages (emm_handle))
                  exit(1);
          }











          Writing Programs That Use Expanded Memory                      18





          Example 2

          This program shows you how to use the basic functions of the LIM
          Expanded Memory Specification with Turbo Pascal.  The program
          does the following:

               1.  Makes sure the LIM Expanded Memory Manager (EMM) has
                   been installed.

               2.  Displays the version number of the EMM.

               3.  Determines if there are enough pages of memory for the
                   program.  It then displays the total number of EMM pages
                   present in the system and the number available for use.

               4.  Requests the desired number of pages from the EMM.

               5.  Maps a logical page into one of the physical pages.

               6.  Displays the base address of our EMM memory page frame. 
                   Performs a simple read/write test on the EMM memory.

               7.  Returns the EMM memory given to us back to the EMM.

               8.  Exits.

          All the calls are structured to return the result or error code
          of the Expanded Memory function performed as an integer.  If the
          error code is not zero, an error has occurred, a simple error
          procedure is called, and the program terminates.

          Type
            ST3  = string[3];
            ST80 = string[80];
            ST5  = string[5];

            Registers = record
              case integer of
                1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,FLAGS: Integer);
                2: (AL,AH,BL,BH,CL,CH,DL,DH         : Byte);
              end;

          Const
            EMM_INT                    = $67;
            DOS_Int                    = $21;
            GET_PAGE_FRAME             = $41;
            GET_UNALLOCATED_PAGE_COUNT = $42;
            ALLOCATE_PAGES             = $43;
            MAP_PAGES                  = $44;
            DEALLOCATE_PAGES           = $45;
            GET_VERSION                = $46;
            STATUS_OK                  = 0;

          Writing Programs That Use Expanded Memory                      19





            {------------------------------------------------------------}
            { Assume the application needs one EMM page.                 }
            {------------------------------------------------------------}
            APPLICATION_PAGE_COUNT = 1;

          Var
            Regs: Registers;

            Emm_handle,
            Page_Frame_Base_Address,
            Pages_Needed,
            Physical_Page,
            Logical_Page,
            Offset,
            Error_Code,
            Pages_EMM_Available,
            Total_EMM_Pages,
            Available_EMM_Pages: Integer;

            Version_Number,
            Pages_Number_String: ST3;

            Verify: Boolean;

            {------------------------------------------------------------}
            { The function Hex_String converts an integer into a four    }
            { character hexadecimal number (string) with leading zeros.  }
            {------------------------------------------------------------}
            Function Hex_String (Number: Integer): ST5;
              Function Hex_Char (Number: Integer): Char;
                Begin
                  If Number < 10 then
                    Hex_Char := Char (Number + 48)
                  else
                    Hex_Char := Char (Number + 55);
                end; { Function Hex_char }

            Var
              S: ST5;

            Begin
              S := '';
              S := Hex_Char ((Number shr 1) div 2048);
              Number := (((Number shr 1) mod 2048) shl 1) + (Number and 1);
              S := S + Hex_Char (Number div 256);
              Number := Number mod 256;
              S := S + Hex_Char (Number div 16);
              Number := Number mod 16;
              S := S + Hex_Char (Number);
              Hex_String := S + 'h';
            end; { Function Hex_String }


          Writing Programs That Use Expanded Memory                      20





            {------------------------------------------------------------}
            { The function Emm_Installed checks to see if the            }
            { EMM is loaded in memory.  It does this by looking          }
            { for the string 'EMMXXXX0', which should be located         }
            { at 10 bytes from the beginning of the code segment the     }
            { EMM interrupt, 67h, points to.                             }
            {------------------------------------------------------------}
            Function Emm_Installed: Boolean;
              Var
                Emm_Device_Name   : string[8];
                Int_67_Device_Name: string[8];
                Position          : integer;
                Regs              : registers;

              Begin
                Int_67_Device_Name := '';
                Emm_Device_Name    := 'EMMXXXX0';
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Get the code segment interrupt 67h points to       }
                    { the EMM interrupt by using DOS function 35h.       }
                    { (get interrupt vector)                             }
                    {----------------------------------------------------}
                    AH := $35;
                    AL := EMM_INT;
                    Intr (DOS_Int, Regs);
                    {----------------------------------------------------}
                    { The ES pseudo-register contains the segment        }
                    { address pointed to by interrupt 67h.  Create an    }
                    { eight character string from the eight successive   }
                    { bytes at address ES:$000A (10 bytes from ES)       }
                    {----------------------------------------------------}
                    For Position := 0 to 7 do
                      Int_67_Device_Name :=
                        Int_67_Device_Name + Chr (mem[ES:Position + $0A]);
                    Emm_Installed := True;
                    {----------------------------------------------------}
                    { If the string is the EMM manager signature,        }
                    { 'EMMXXXX0', then EMM is installed and ready for    }
                    { use.  If not, then EMM is not present.             }
                    {----------------------------------------------------}
                    If Int_67_Device_Name <> Emm_Device_Name
                      then Emm_Installed := False;
                  end; { with Regs do }
              end; { Function Emm_Installed }







          Writing Programs That Use Expanded Memory                      21





            {------------------------------------------------------------}
            { This function returns the total number of EMM pages        }
            { present in the system, and the number of EMM pages that    }
            { are available.                                             }
            {------------------------------------------------------------}
            Function EMM_Pages_Available
              (Var Total_EMM_Pages, Pages_Available: Integer): Integer;
              Var
                Regs: Registers;

              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Get the number of currently unallocated pages and  }
                    { the total number of pages in the system from EMM.  }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = get unallocated page count function        }
                    {----------------------------------------------------}
                    AH := GET_UNALLOCATED_PAGE_COUNT;
                    Intr (EMM_INT, Regs);
                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    BX = currently unallocated pages                }
                    {    DX = total pages in the system                  }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Pages_Available := BX;
                    Total_EMM_Pages := DX;
                    EMM_Pages_Available := AH;
                  end;
              end; { Function EMM_Pages_Available }


            {------------------------------------------------------------}
            { This function requests the specified number of pages       }
            { from the EMM.                                              }
            {------------------------------------------------------------}
            Function Allocate_Expanded_Memory_Pages
              (Pages_Needed: Integer; Var Handle: Integer): Integer;
              Var
                Regs: Registers;











          Writing Programs That Use Expanded Memory                      22





              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Allocate the specified number of pages from EMM.   }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = allocate pages function.                   }
                    {    BX = number of pages to allocate.               }
                    {----------------------------------------------------}
                    AH := ALLOCATE_PAGES;
                    BX := Pages_Needed;
                    Intr (EMM_INT, Regs);
                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    DX = EMM handle                                 }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Handle := DX;
                    Allocate_Expanded_Memory_Pages := AH;
                  end;
              end; { Function Allocate_Expanded_Memory_Pages }


            {------------------------------------------------------------}
            { This function maps a logical page allocated by the         }
            { Allocate_Expanded_Memory_Pages function into one of the    }
            { four physical pages.                                       }
            {------------------------------------------------------------}
            Function Map_Expanded_Memory_Pages
              (Handle, Logical_Page, Physical_Page: Integer): Integer;
              Var
                Regs: Registers;

              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Map a logical page at a physical page.             }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = map page function                          }
                    {    DX = handle                                     }
                    {    BX = logical page number                        }
                    {    AL = physical page number                       }
                    {----------------------------------------------------}
                    AH := MAP_PAGES;
                    DX := Handle;
                    BX := Logical_Page;
                    AL := Physical_Page;
                    Intr (EMM_INT, Regs);




          Writing Programs That Use Expanded Memory                      23





                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Map_Expanded_Memory_Pages := AH;
                  end; { with Regs do }
              end; { Function Map_Expanded_Memory_Pages }


            {------------------------------------------------------------}
            { This function gets the physical address of the EMM page    }
            { frame we are using.  The address returned is the segment   }
            { of the page frame.                                         }
            {------------------------------------------------------------}
            Function Get_Page_Frame_Base_Address
              (Var Page_Frame_Address: Integer): Integer;
              Var
                Regs: Registers;

              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Get the page frame segment address from EMM.       }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = get page frame segment function            }
                    {----------------------------------------------------}
                    AH := GET_PAGE_FRAME;
                    Intr (EMM_INT, Regs);
                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    BX = page frame segment address                 }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Page_Frame_Address := BX;
                    Get_Page_Frame_Base_Address := AH;
                  end; { with Regs do }
              end; { Function Get_Page_Frame_Base_Address }


            {------------------------------------------------------------}
            { This function releases the EMM memory pages allocated to   }
            { us, back to the EMM memory pool.                           }
            {------------------------------------------------------------}
            Function Deallocate_Expanded_Memory_Pages
              (Handle: Integer): Integer;
              Var
                Regs: Registers;





          Writing Programs That Use Expanded Memory                      24





              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Deallocate the pages allocated to an EMM handle.   }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = deallocate pages function                  }
                    {    DX = EMM handle                                 }
                    {----------------------------------------------------}
                    AH := DEALLOCATE_PAGES;
                    DX := Handle;
                    Intr (EMM_INT, Regs);
                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Deallocate_Expanded_Memory_Pages := AH;
                  end; { with Regs do }
              end; { Function Deallocate_Expanded_Memory_Pages }


            {------------------------------------------------------------}
            { This function returns the version number of the EMM as     }
            { a three-character string.                                  }
            {------------------------------------------------------------}
            Function Get_Version_Number (Var Version_String: ST3): Integer;
              Var
                Regs: Registers;
                Integer_Part, Fractional_Part: Char;

              Begin
                with Regs do
                  Begin
                    {----------------------------------------------------}
                    { Get the version of EMM.                            }
                    { Load pseudo-registers prior to invoking EMM.       }
                    {    AH = get EMM version function                   }
                    {----------------------------------------------------}
                    AH := GET_VERSION;
                    Intr (EMM_INT, Regs);













          Writing Programs That Use Expanded Memory                      25





                    {----------------------------------------------------}
                    { If the version number returned was OK, then        }
                    { convert it to a three-character string.            }
                    {----------------------------------------------------}
                    If AH=STATUS_OK then
                      Begin
                        {------------------------------------------------}
                        { The upper four bits of AH are the integer      }
                        { portion of the version number, the lower four  }
                        { bits are the fractional portion.  Convert the  }
                        { integer value to ASCII by adding 48.           }
                        {------------------------------------------------}
                        Integer_Part    := Char (AL shr 4  + 48);
                        Fractional_Part := Char (AL and $F + 48);
                        Version_String  := Integer_Part + '.' +
                                                          Fractional_Part;
                      end; { If AH=STATUS_OK }
                    {----------------------------------------------------}
                    { Unload the pseudo-registers after invoking EMM.    }
                    {    AH = status                                     }
                    {----------------------------------------------------}
                    Get_Version_Number := AH;
                  end; { with Regs do }
              end; { Function Get_Version_Number }


            {------------------------------------------------------------}
            { This procedure prints an error message passed by the       }
            { caller, prints the error code passed by the caller in hex, }
            { and then terminates the program with an error level of 1.  }
            {------------------------------------------------------------}
            Procedure Error (Error_Message: ST80; Error_Number: Integer);
              Begin
                Writeln (Error_Message);
                Writeln ('  Error_Number = ', Hex_String (Error_Number));
                Writeln ('EMM test program aborting.');
                Halt (1);
              end; { Procedure Error }


          {--------------------------------------------------------------}
          { This program is an example of the basic EMM functions that   }
          { you need in order to use EMM memory with Turbo Pascal.       }
          {--------------------------------------------------------------}
          Begin
            ClrScr;
            Window (5,2,77,22);






          Writing Programs That Use Expanded Memory                      26





            {------------------------------------------------------------}
            { Determine if the Expanded Memory Manager is installed.  If }
            { not, then terminate 'main' with an ErrorLevel code of 1.   }
            {------------------------------------------------------------}
            If not (Emm_Installed) then
              Begin
                Writeln ('The LIM EMM is not installed.');
                Halt (1);
              end
            else
              Begin
                { Get the version number and display it }
                Error_Code := Get_Version_Number (Version_Number);
                If Error_Code <> STATUS_OK then
                  Error ('Error getting EMM version number.', Error_Code)
                else
                  Writeln ('LIM Expanded Memory Manager, version ',
                           Version_Number, ' is ready for use.');
              end;
            Writeln;

            {------------------------------------------------------------}
            { Determine if there are enough expanded memory pages for    }
            { this application.                                          }
            {------------------------------------------------------------}
            Pages_Needed := APPLICATION_PAGE_COUNT;
            Error_Code   := EMM_Pages_Available (Total_EMM_Pages,
                                                 Available_EMM_Pages);
            If Error_Code <> STATUS_OK then
              Error ('Error determining number of EMM pages available.',
                     Error_Code);
            Writeln ('There are a total of ', Total_EMM_Pages,
                     ' expanded memory pages present in this system.');
            Writeln ('  ', Available_EMM_Pages,
                     ' of those pages are available for use.');
            Writeln;

            {------------------------------------------------------------}
            { If there is an insufficient number of pages for the        }
            { application, then report the error and terminate the EMM   }
            { example program.                                           }
            {------------------------------------------------------------}
            If Pages_Needed > Available_EMM_Pages then
              Begin
                Str (Pages_Needed, Pages_Number_String);
                Error ('We need ' + Pages_Number_String +
                       ' EMM pages.  There are not that many available.',
                       Error_Code);
              end; { Pages_Needed > Available_EMM_Pages }




          Writing Programs That Use Expanded Memory                      27





            {------------------------------------------------------------}
            { Allocate expanded memory pages for our use.                }
            {------------------------------------------------------------}
            Error_Code :=
              Allocate_Expanded_Memory_Pages (Pages_Needed, Emm_Handle);
            Str (Pages_Needed, Pages_Number_String);
            If Error_Code <> STATUS_OK then
              Error ('EMM test program failed trying to allocate '
                     + Pages_Number_String
                     + ' pages for usage.', Error_Code);
            Writeln (APPLICATION_PAGE_COUNT,
                     ' EMM page(s) allocated for the EMM test program.');
            Writeln;

            {------------------------------------------------------------}
            { Map in the required logical pages to the physical pages    }
            { given to us, in this case just one page.                   }
            {------------------------------------------------------------}
            Logical_Page  := 0;
            Physical_Page := 0;
            Error_Code := Map_Expanded_Memory_Pages (Emm_Handle,
                                                     Logical_Page,
                                                     Physical_Page);
            If Error_Code <> STATUS_OK then
              Error ('EMM test program failed trying to map '
                     + 'logical pages into physical pages.',
                     Error_Code);

            Writeln ('Logical Page ',
                     Logical_Page,
                     ' successfully mapped into Physical Page ',
                     Physical_Page);
            Writeln;

            {------------------------------------------------------------}
            { Get the expanded memory page frame address.                }
            {------------------------------------------------------------}
            Error_Code := Get_Page_Frame_Base_Address
                            (Page_Frame_Base_Address);
            If Error_Code <> STATUS_OK then
              Error ('EMM test program unable to get the base Page'
                     + ' Frame Address.',
                     Error_Code);
            Writeln ('The base address of the EMM page frame is = '
                     + Hex_String (Page_Frame_Base_Address));
            Writeln;







          Writing Programs That Use Expanded Memory                      28





            {------------------------------------------------------------}
            { Write a test pattern to expanded memory.                   }
            {------------------------------------------------------------}
            For Offset := 0 to 16382 do
              Begin
                Mem[Page_Frame_Base_Address:Offset] := Offset mod 256;
              end;

            {------------------------------------------------------------}
            { Make sure that what is in EMM memory is what was just      }
            { written.                                                   }
            {------------------------------------------------------------}
            Writeln ('Testing EMM memory.');

            Offset := 1;
            Verify := True;
            while (Offset <= 16382) and (Verify = True) do
              Begin
                If Mem[Page_Frame_Base_Address:Offset] <> Offset mod 256
                  then Verify := False;
                Offset := Succ (Offset);
              end; { while (Offset <= 16382) and (Verify = True) }

            {------------------------------------------------------------}
            { If what is read does not match what was written,           }
            { an error occurred.                                         }
            {------------------------------------------------------------}
            If not Verify then
              Error ('What was written to EMM memory was not found during'
                     + ' memory verification test.',
                     0);
            Writeln ('EMM memory test successful.');
            Writeln;

            {------------------------------------------------------------}
            { Return the expanded memory pages given to us back to the   }
            { EMM memory pool before terminating our test program.       }
            {------------------------------------------------------------}
            Error_Code := Deallocate_Expanded_Memory_Pages (Emm_Handle);
            If Error_Code <> STATUS_OK then
              Error ('EMM test program was unable to deallocate '
                     + 'the EMM pages in use.',
                     Error_Code);
            Writeln (APPLICATION_PAGE_COUNT,
                     ' pages(s) deallocated.');
            Writeln;
            Writeln ('EMM test program completed.');

          end.




          Writing Programs That Use Expanded Memory                      29





          Example 3

               This program is written in Microsoft's macro assembler.


          CODE SEGMENT
               ASSUME CS:CODE, DS:CODE

          MOV   AX,CS
          MOV   DX,AX
               .
               .
               .
          check_emm_installed:

          MOV   AH,35h                  ; AH = DOS get interrupt vector
                                        ; function
          MOV   AL,67h                  ; AL = EMM interrupt vector number
          INT   21h
          MOV   DI,0Ah                  ; ES:DI points to where device     
                                        ; name should be
          LEA   SI,EMM_device_name      ; DS:SI points to ASCII string     
                                        ; containing EMM device name

          MOV   CX,device_name_length   ; set up loop counter for string op
          CLD                           ; set up direction flag for forward
          REPE  CMPSB                   ; Compare the strings
          JNE   exit                    ; IF strings not equal THEN exit
                                        ; ELSE
          check_enough_unallocated_pages:

          MOV   AH,41h                  ;    AH = EMM get unallocated page
                                        ;    count function code
          INT   67h
          OR    AH,AH                   ; Check EMM status
          JNZ   emm_error_handler       ; IF error THEN goto error handler
                                        ; ELSE
          allocate_expanded_memory_pages:

          MOV   AH,43h                  ;    AH = EMM allocate pages
                                        ;    function code
          MOV   BX,2                    ;    BX = number of pages needed
          INT   67h
          OR    AH,AH                   ; Check EMM status
          JNZ   emm_error_handler       ; IF error THEN goto error handler
                                        ; ELSE
          MOV   emm_handle,DX           ;    save EMM handle

          map_expanded_memory_pages:

          MOV   AH,44h                  ; AH = EMM map pages function
          MOV   DX,emm_handle           ; DX = application's handle

          Writing Programs That Use Expanded Memory                      30





          map_0_to_0:

          MOV   BX,0                    ; BX = logical page 0
          MOV   AL,0                    ; AL = physical page 0
          INT   67h
          OR    AH,AH                   ; Check EMM status
          JNZ   emm_error_handler       ; If error THEN goto error handler
                                        ; ELSE
          get_page_frame_address:

          MOV   AH,41h                  ; AH = EMM get page frame base
                                        ; address function
          INT   67h
          OR    AH,AH                   ; Check EMM status
          JNZ   emm_error_handler       ; IF error THEN goto error handler
          MOV   pf_addr,BX              ; ELSE save pf_addr

          write_to_expanded_memory:     ; Write zeros to memory mapped at
                                        ; physical page 0
          MOV   AX,pf_addr
          MOV   ES,AX                   ; ES points to physical page 0
          MOV   DI,0                    ; DI indexes into physical page 0
          MOV   AL,0                    ; Initialize AL for string STOSB
          MOV   CX,4000h                ; Initialize loop counter to length 
                                        ; of expanded memory page size
          CLD                           ; set up direction flag for forward
          REP   STOSB

          deallocate_pages:

          MOV   AH,45h                  ; AH = EMM deallocate pages        
                                        ; function
          MOV   DX,emm_handle
          INT   67h                     ; return handle's pages to EMM
          OR    AH,AH                   ; Check EMM status
          JNZ   emm_error_handler       ; IF error THEN goto error handler

          exit:

          MOV   AH,4Ch                  ; AH = DOS exit function
          INT   21h                     ; return to DOS


          EMM_device_name DB 'EMMXXXX0' ; ASCII EMM device name string

          device_name_length EQU 8

          CODE ENDS
               END




          Writing Programs That Use Expanded Memory                      31





          Example 4

               This program is an example of how to exchange a 256K-byte
               block of data from conventional memory to expanded memory.


          CODE SEGMENT
               ASSUME CS:CODE, DS:CODE
               .
               .
               .
          xchg_packet_set_up:

          ;DS:SI = xchg_packet

          MOV   AX,SEG xchg_packet
          MOV   DS,AX
          MOV   SI,OFFSET xchg_packet

          ;Moving 256K of data from conventional memory to expanded memory

          MOV   WORD PTR [SI].region_length[0],0
          MOV   WORD PTR [SI].region_length[2],4
          MOV   [SI].src_mem_type,0
          MOV   [SI].dest_mem_type,1

          ;starting at segment: 4000h, offset: 0

          MOV   [SI].src_init_seg_page,4000h
          MOV   [SI].src_init_offset,0

          ;Move data into expanded memory logical page 0, offset 0.

          MOV   [SI].dest_init_seg_page,0
          MOV   [SI].dest_init_offset,0

          ;Initialize for future compatibility

          MOV   [SI].src_handle,0

          ;Need handle for expanded memory destination.

          MOV   DX,emm_handle
          MOV   [SI].dest_handle,DX

          ;AX = EMM Exchange Memory function

          MOV   AX,5701h
          INT   67h
          OR    AH,AH
          JNZ   emm_error_handler


          Writing Programs That Use Expanded Memory                      32





          xchg_struct                    STRUC
             region_length               DD ?
             src_mem_type                DB ?
             src_handle                  DW ?
             src_init_offset             DW ?
             src_init_seg_page           DW ?
             dest_mem_type               DB ?
             dest_handle                 DW ?
             dest_init_offset            DW ?
             dest_init_seg_page          DW ?
          xchg_struct                    ENDS

          xchg_packet                    xchg_struct

          CODE  ENDS
                END





































          Writing Programs That Use Expanded Memory                      33





          Chapter 3
          EMM FUNCTIONS


               This chapter provides you with a standardized set of
               expanded memory functions.  Because they are standardized,
               you avoid potential compatibility problems with other
               expanded memory programs that also adhere to the memory
               manager specification.  Programs that deal directly with the
               hardware or that don't adhere to this specification will be
               incompatible.

               Table 3-1 presents a sequential list of the EMM functions. 
               The remainder of this chapter provides detailed descriptions
               of each function.


          Table 3-1.  List of EMM Functions
          ----------------------------------------------------------------

          Number             Function Name                Hex Value   Page

          ----------------------------------------------------------------

             1    Get Status                                40h         37

             2    Get Page Frame Address                    41h         38

             3    Get Unallocated Page Count                42h         40

             4    Allocate Pages                            43h         42

             5    Map/Unmap Handle Page                     44h         46

             6    Deallocate Pages                          45h         49

             7    Get Version                               46h         51

             8    Save Page Map                             47h         53

             9    Restore Page Map                          48h         55

            10    Reserved                                  49h         57

            11    Reserved                                  4Ah         58

            12    Get Handle Count                          4Bh         59

            13    Get Handle Pages                          4Ch         61

            14    Get All Handle Pages                      4Dh         63


          EMM Functions                                                  34





          Table 3-1.  List of EMM Functions (continued)
          ----------------------------------------------------------------

          Number             Function Name                Hex Value   Page

          ----------------------------------------------------------------

            15    Get Page Map                              4E00h       65
                  Set Page Map                              4E01h       67
                  Get & Set Page Map                        4E02h       69
                  Get Size of Page Map Save Array           4E03h       71

            16    Get Partial Page Map                      4F00h       73
                  Set Partial Page Map                      4F01h       76
                  Get Size of Partial Page Map
                     Save Array                             4F02h       78

            17    Map/Unmap Multiple Handle Pages
                  (Physical page number mode)               5000h       82
                  Map/Unmap Multiple Handle Pages
                  (Segment address mode)                    5001h       85

            18    Reallocate Pages                          51h         88

            19    Get Handle Attribute                      5200h       92
                  Set Handle Attribute                      5201h       94
                  Get Handle Attribute Capability           5202h       96

            20    Get Handle Name                           5300h       98
                  Set Handle Name                           5301h      100

            21    Get Handle Directory                      5400h      102
                  Search for Named Handle                   5401h      105
                  Get Total Handles                         5402h      107

            22    Alter Page Map & Jump
                  (Physical page number mode)               5500h      109
                  Alter Page Map & Jump
                  (Segment address mode)                    5501h      109

            23    Alter Page Map & Call
                  (Physical page number mode)               5600h      113
                  Alter Page Map & Call
                  (Segment address mode)                    5601h      113
                  Get Page Map Stack Space Size             5602h      118

            24    Move Memory Region                        5700h      120
                  Exchange Memory Region                    5701h      126

            25    Get Mappable Physical Address Array       5800h      132
                  Get Mappable Physical Address Array
                     Entries                                5801h      136

          EMM Functions                                                  35





          Table 3-1.  List of EMM Functions (continued)
          ----------------------------------------------------------------

          Number             Function Name                Hex Value   Page

          ----------------------------------------------------------------

            26    Get Hardware Configuration Array          5900h      138
                  Get Unallocated Raw Page Count            5901h      142

            27    Allocate Standard Pages                   5A00h      144
                  Allocate Raw Pages                        5A01h      147

            28    Get Alternate Map Register Set            5B00h      153
                  Set Alternate Map Register Set            5B01h      157
                  Get Alternate Map Save Array Size         5B02h      161
                  Allocate Alternate Map Register Set       5B03h      163
                  Deallocate Alternate Map Register Set     5B04h      166
                  Allocate DMA Register Set                 5B05h      168
                  Enable DMA on Alternate Map
                     Register Set                           5B06h      170
                  Disable DMA on Alternate Map
                     Register Set                           5B07h      173
                  Deallocate DMA Register Set               5B08h      175

            29    Prepare Expanded Memory Hardware
                     for Warmboot                           5Ch        177

            30    Enable OS/E Function Set                  5D00h      179
                  Disable OS/E Function Set                 5D01h      182
                  Return OS/E Access Key                    5D02h      185

          ----------------------------------------------------------------




















          EMM Functions                                                  36





          Function 1. Get Status



          PURPOSE

               The Get Status function returns a status code indicating
               whether the memory manager is present and the hardware is
               working correctly.


          CALLING PARAMETERS

               AH = 40h
                   Contains the Get Status Function.


          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager is present in the system, and the hardware
                   is working correctly.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.


          EXAMPLE

          MOV   AH,40h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error






          EMM Functions                                                  37





          Function 2. Get Page Frame Address



          PURPOSE

               The Get Page Frame Address function returns the segment
               address where the page frame is located.


          CALLING PARAMETERS

               AH = 41h
                   Contains the Get Page Frame Address function.


          RESULTS

               These results are valid only if the status returned is zero.

               BX = page frame segment address
                   Contains the segment address of the page frame.


          REGISTERS MODIFIED

               AX, BX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has returned the page frame address in the
                   BX register.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.







          EMM Functions                                                  38





          Function 2. Get Page Frame Address



          EXAMPLE

          page_frame_segment             DW ?

          MOV   AH,41h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error
          MOV   page_frame_segment,BX    ; save page frame address








































          EMM Functions                                                  39





          Function 3. Get Unallocated Page Count



          PURPOSE

               The Get Unallocated Page Count function returns the number
               of unallocated pages and the total number of expanded memory
               pages.


          CALLING PARAMETERS

               AH = 42h
                   Contains the Get Unallocated Page Count function.


          RESULTS

               These results are valid only if the status returned is zero.

               BX = unallocated pages
                   The number of expanded memory pages that are currently
                   available for use (unallocated).

               DX = total pages
                   The total number of expanded memory pages.


          REGISTERS MODIFIED

               AX, BX, DX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has returned the number of unallocated pages
                   and the number of total pages in expanded memory.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.


          EMM Functions                                                  40





          Function 3. Get Unallocated Page Count



          EXAMPLE

          un_alloc_pages                 DW ?
          total_pages                    DW ?

          MOV   AH,42h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error
          MOV   un_alloc_pages,BX        ; save unallocated page count
          MOV   total_pages,DX           ; save total page count






































          EMM Functions                                                  41





          Function 4. Allocate Pages



               The Allocate Pages function allocates the number of pages
               requested and assigns a unique EMM handle to these pages. 
               The EMM handle owns these pages until the application
               deallocates them.

               Handles which are assigned using this function will have
               16K-byte pages, the size of a standard expanded memory page. 
               If the expanded memory board hardware isn't able to supply
               16K-byte pages, it will emulate them by combining multiple
               non-standard size pages to form a single 16K-byte page.  All
               application programs and functions that use the handles this
               function returns will deal with 16K-byte pages.

               The numeric value of the handles the EMM returns are in the
               range of 1 to 254 decimal (0001h to 00FEh).  The OS handle
               (handle value 0) is never returned by the Allocate Pages
               function.  Also, the uppermost byte of the handle will be
               zero and cannot be used by the application.  A memory
               manager should be able to supply up to 255 handles, includ-
               ing the OS handle.  An application can use Function 21 to
               find out how many handles an EMM supports.

               Allocating zero pages to a handle is not valid.  If an
               application needs to allocate 0 pages to a handle it should
               use Function 27 (Allocate Standard Pages subfunction)
               provided for this purpose.

          Note............................................................
               This note affects expanded memory manager implementors and
               operating system developers only.  Applications should not
               use the following characteristics of the memory manager.  An
               application violating this rule will be incompatible with
               future versions of Microsoft's operating systems and
               environments.

               To be compatible with this specification, an expanded memory
               manager will provide a special handle which is available to
               the operating system only.  This handle will have a value of
               0000h and will have a set of pages allocated to it when the
               expanded memory manager driver installs.  The pages that the
               memory manager will automatically allocate to handle 0000h
               are those that backfill conventional memory.  Typically,
               this backfill occurs between addresses 40000h (256K) and
               9FFFFh (640K).  However, the range can extend below and
               above this limit if the hardware and memory manager have the
               capability.



          EMM Functions                                                  42





          Function 4. Allocate Pages



               An operating system won't have to invoke Function 4 to
               obtain this handle because it can assume the handle already
               exists and is available for use immediately after the
               expanded memory device driver installs.  When an operating
               system wants to use this handle, it uses the special handle
               value of 0000h.  The operating system will be able to invoke
               any EMM function using this special handle value.  To
               allocate pages to this handle, the operating system need
               only invoke Function 18 (Reallocate Pages).

               There are two special cases for this handle:

               1.  Function 4 (Allocate Pages).  This function must never
                   return zero as a handle value.  Applications must always
                   invoke Function 4 to allocate pages and obtain a handle
                   which identifies the pages which belong to it.  Since
                   Function 4 never returns a handle value of zero, an
                   application will never gain access to this special
                   handle.

               2.  Function 6 (Deallocate Pages).  If the operating system
                   uses it to deallocate the pages which are allocated to
                   this special handle, the pages the handle owns will be
                   returned to the manager for use.  But the handle will
                   not be available for reassignment.  The manager should
                   treat a deallocate pages function request for this
                   handle the same as a reallocate pages function request,
                   where the number of pages to reallocate to this handle
                   is zero.


          CALLING PARAMETERS

               AH = 43h
                   Contains the Allocate Pages function.

               BX = num_of_pages_to_alloc
                   Contains the number of pages you want your program to
                   allocate.










          EMM Functions                                                  43





          Function 4. Allocate Pages



          RESULTS

               These results are valid only if the status returned is zero.

               DX = handle
                   Contains a unique EMM handle.  Your program must use
                   this EMM handle (as a parameter) in any function that
                   requires it.  You can use up to 255 handles.  The
                   uppermost byte of the handle will be zero and cannot be
                   used by the application.


          REGISTERS MODIFIED

               AX, DX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has allocated the requested pages to the
                   assigned EMM handle.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.

               AH = 85h   RECOVERABLE.
                   All EMM handles are being used.

               AH = 87h   RECOVERABLE.
                   There aren't enough expanded memory pages present in the
                   system to satisfy your program's request.

               AH = 88h   RECOVERABLE.
                   There aren't enough unallocated pages to satisfy your
                   program's request.

               AH = 89h   RECOVERABLE.
                   Your program attempted to allocate zero pages.

          EMM Functions                                                  44





          Function 4. Allocate Pages



          EXAMPLE

          num_of_pages_to_alloc          DW ?
          emm_handle                     DW ?

          MOV   BX,num_of_pages_to_alloc ; load number of pages
          MOV   AH,43h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error
          MOV   emm_handle,DX            ; save EMM handle






































          EMM Functions                                                  45





          Function 5. Map/Unmap Handle Pages



          PURPOSE

               The Map/Unmap Handle Page function maps a logical page at a
               specific physical page anywhere in the mappable regions of
               system memory.  The lowest valued physical page numbers are
               associated with regions of memory outside the conventional
               memory range.  Use Function 25 (Get Mappable Physical
               Address Array) to determine which physical pages within a
               system are mappable and determine the segment addresses
               which correspond to a specific physical page number. 
               Function 25 provides a cross reference between physical page
               numbers and segment addresses.

               This function can also unmap physical pages, making them
               inaccessible for reading or writing.  You unmap a physical
               page by setting its associated logical page to FFFFh.

               You might unmap an entire set of mapped pages, for example,
               before loading and executing a program.  Doing so ensures
               the loaded program, if it accesses expanded memory, won't
               access the pages your program has mapped.  However, you must
               save the mapped context before you unmap the physical pages. 
               This enables you to restore it later so you can access the
               memory you mapped there.  To save the mapping context, use
               Function 8, 15, or 16.  To restore the mapping context, use
               Function 9, 15, or 16.

               The handle determines what type of pages are being mapped. 
               Logical pages allocated by Function 4 and Function 27
               (Allocate Standard Pages subfunction) are referred to as
               pages and are 16K bytes long.  Logical pages allocated by
               Function 27 (Allocate Raw Pages subfunction) are referred to
               as raw pages and might not be the same size as logical
               pages.


          CALLING PARAMETERS

               AH = 44h
                   Contains the Map Handle Page function.

               AL = physical_page_number
                   Contains the number of the physical page into which the
                   logical page number is to be mapped.  Physical pages are
                   numbered zero-relative.




          EMM Functions                                                  46





          Function 5. Map/Unmap Handle Pages



               BX = logical_page_number
                   Contains the number of the logical page to be mapped at
                   the physical page within the page frame.  Logical pages
                   are numbered zero-relative.  The logical page must be in
                   the range zero through (number of pages allocated to the
                   EMM handle - 1).  However, if BX contains logical page
                   number FFFFh, the physical page specified in AL will be
                   unmapped (be made inaccessible for reading or writing).

               DX = emm_handle
                   Contains the EMM handle your program received from
                   Function 4 (Allocate Pages).


          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has mapped the page.  The page is ready to
                   be accessed.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 83h   NON-RECOVERABLE.
                   The memory manager couldn't find the EMM handle your
                   program specified.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager isn't
                   defined.

               AH = 8Ah   RECOVERABLE.
                   The logical page is out of the range of logical pages
                   which are allocated to the EMM handle.  This status is
                   also returned if a program attempts to map a logical
                   page when no logical pages are allocated to the handle.



          EMM Functions                                                  47





          Function 5. Map/Unmap Handle Pages



               AH = 8Bh   RECOVERABLE.
                   The physical page number is out of the range of allow-
                   able physical pages.  The program can recover by
                   attempting to map into memory at a physical page which
                   is within the range of allowable physical pages.


          EXAMPLE

          emm_handle                     DW ?
          logical_page_number            DW ?
          physical_page_number           DB ?

          MOV   DX,emm_handle            ; load EMM handle
          MOV   BX,logical_page_number   ; load logical page number
          MOV   AL,physical_page_number  ; load physical page number
          MOV   AH,44h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error





























          EMM Functions                                                  48





          Function 6. Deallocate Pages



          PURPOSE

               Deallocate Pages deallocates the logical pages currently
               allocated to an EMM handle.  Only after the application
               deallocates these pages can other applications use them. 
               When a handle is deallocated, its name is set to all ASCII
               nulls (binary zeros).

          Note............................................................
               A program must perform this function before it exits to DOS. 
               If it doesn't, no other programs can use these pages or the
               EMM handle.  This means that a program using expanded memory
               should trap critical errors and control-break if there is a
               chance that the program will have allocated pages when
               either of these events occur.


          CALLING PARAMETERS

               AH = 45h
                   Contains the Deallocate Pages function.

               DX = handle
                   Contains the EMM handle returned by Function 4 (Allocate
                   Pages).


          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has deallocated the pages previously allo-
                   cated to the EMM handle.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 83h   NON-RECOVERABLE.
                   The manager couldn't find the specified EMM handle.

          EMM Functions                                                  49





          Function 6. Deallocate Pages



               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.

               AH = 86h   RECOVERABLE.
                   The memory manager detected a save or restore page
                   mapping context error (Function 8 or 9).  There is a
                   page mapping register state in the save area for the
                   specified EMM handle.  Save Page Map (Function 8) placed
                   it there and a subsequent Restore Page Map (Function 9)
                   has not removed it.

                   If you have saved the mapping context, you must restore
                   it before you deallocate the EMM handle's pages.


          EXAMPLE

          emm_handle                     DW ?

          MOV   DX,emm_handle            ; load EMM handle
          MOV   AH,45h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error
























          EMM Functions                                                  50





          Function 7. Get Version



          PURPOSE

               The Get Version function returns the version number of the
               memory manager software.


          CALLING PARAMETERS

               AH = 46h
                   Contains the Get Version function.


          RESULTS

               These results are valid only if the status returned is zero.

               AL = version number
                   Contains the memory manager's version number in binary
                   coded decimal (BCD) format.  The upper four bits contain
                   the integer digit of the version number.  The lower four
                   bits contain the fractional digit of version number. 
                   For example, version 4.0 is represented like this:

                                      0100 0000
                                        /   \
                                       4  .  0

                   When checking for a version number, an application
                   should check for a version number or greater.  Vendors
                   may use the fractional digit to indicate enhancements or
                   corrections to their memory managers.  Therefore, to
                   allow for future versions of memory managers, an
                   application shouldn't depend on an exact version number.


          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager is present in the system and the hardware is
                   working correctly.




          EMM Functions                                                  51





          Function 7. Get Version



               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.


          EXAMPLE

          emm_version                    DB ?

          MOV   AH,46h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error
          MOV   emm_version,AL           ; save version number



























          EMM Functions                                                  52





          Function 8. Save Page Map



          PURPOSE

               Save Page Map saves the contents of the page mapping
               registers on all expanded memory boards in an internal save
               area.  The function is typically used to save the memory
               mapping context of the EMM handle that was active when a
               software or hardware interrupt occurred.  (See Function 9,
               Restore Page Map, for the restore operation.)

               If you're writing a resident program, an interrupt service
               routine, or a device driver that uses expanded memory, you
               must save the state of the mapping hardware.  You must save
               this state because application software using expanded
               memory may be running when your program is invoked by a
               hardware interrupt, a software interrupt, or DOS.

               The Save Page Map function requires the EMM handle that was
               assigned to your resident program, interrupt service
               routine, or device driver at the time it was initialized. 
               This is not the EMM handle that the application software was
               using when your software interrupted it.

               The Save Page Map function saves the state of the map
               registers for only the 64K-byte page frame defined in
               versions 3.x of this specification.  Since all applications
               written to LIM versions 3.x require saving the map register
               state of only this 64K-byte page frame, saving the entire
               mapping state for a large number of mappable pages would be
               inefficient use of memory.  Applications that use a mappable
               memory region outside the LIM 3.x page frame should use
               Function 15 or 16 to save and restore the state of the map
               registers.


          CALLING PARAMETERS

               AH = 47h
                   Contains the Save Page Map function.

               DX = handle
                   Contains the EMM handle assigned to the interrupt
                   service routine that's servicing the software or
                   hardware interrupt.  The interrupt service routine needs
                   to save the state of the page mapping hardware before
                   mapping any pages.




          EMM Functions                                                  53





          Function 8. Save Page Map



          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has saved the state of the page mapping
                   hardware.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 83h   NON-RECOVERABLE.
                   The memory manager couldn't find the EMM handle your
                   program specified.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.

               AH = 8Ch   NON-RECOVERABLE.
                   There is no room in the save area to store the state of
                   the page mapping registers.  The state of the map
                   registers has not been saved.

               AH = 8Dh   CONDITIONALLY-RECOVERABLE.
                   The save area already contains the page mapping register
                   state for the EMM handle your program specified.


          EXAMPLE

          emm_handle                     DW ?

          MOV   DX,emm_handle            ; load EMM handle
          MOV   AH,47h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error



          EMM Functions                                                  54





          Function 9. Restore Page Map



          PURPOSE

               The Restore Page Map function restores the page mapping
               register contents on the expanded memory boards for a
               particular EMM handle.  This function lets your program
               restore the contents of the mapping registers its EMM handle
               saved.  (See Function 8, Save Page Map for the save opera-
               tion.)

               If you're writing a resident program, an interrupt service
               routine, or a device driver that uses expanded memory, you
               must restore the mapping hardware to the state it was in
               before your program took over.  You must save this state
               because application software using expanded memory might
               have been running when your program was invoked.

               The Restore Page Map function requires the EMM handle that
               was assigned to your resident program, interrupt service
               routine, or device driver at the time it was initialized. 
               This is not the EMM handle that the application software was
               using when your software interrupted it.

               The Restore Page Map function restores the state of the map
               registers for only the 64K-byte page frame defined in
               versions 3.x of this specification.  Since all applications
               written to LIM versions 3.x require restoring the map
               register state of only this 64K-byte page frame, restoring
               the entire mapping state for a large number of mappable
               pages would be inefficient use of memory.  Applications that
               use a mappable memory region outside the LIM 3.x page frame
               should use Function 15 or 16 to save and restore the state
               of the map registers.


          CALLING PARAMETERS

               AH = 48h
                   Contains the Restore Page Map function.

               DX = emm_handle
                   Contains the EMM handle assigned to the interrupt
                   service routine that's servicing the software or
                   hardware interrupt.  The interrupt service routine needs
                   to restore the state of the page mapping hardware.





          EMM Functions                                                  55





          Function 9. Restore Page Map



          REGISTERS MODIFIED

               AX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has restored the state of the page mapping
                   registers.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 83h   NON-RECOVERABLE.
                   The memory manager couldn't find the EMM handle your
                   program specified.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.

               AH = 8Eh   CONDITIONALLY-RECOVERABLE.
                   There is no page mapping register state in the save area
                   for the specified EMM handle.  Your program didn't save
                   the contents of the page mapping hardware, so Restore
                   Page can't restore it.


          EXAMPLE

          emm_handle                     DW ?

          MOV   DX,emm_handle            ; load EMM handle
          MOV   AH,48h                   ; load function code
          INT   67h                      ; call the memory manager
          OR    AH,AH                    ; check EMM status
          JNZ   emm_err_handler          ; jump to error handler on error






          EMM Functions                                                  56





          Function 10. Reserved



               In earlier versions of the Lotus/Intel/Microsoft Expanded
               Memory Specification, Function 10 returned the page mapping
               register I/O array.  This function is now reserved and new
               programs should not use it.

               Existing programs that use this function may still work
               correctly if the hardware is capable of supporting them. 
               However, programs that use Functions 16 through 30 in
               Version 4.0 of this specification must not use Functions 10
               and 11.  These functions won't work correctly if your
               program attempts to mix the use of the new functions
               (Functions 16 through 30) and Functions 10 and 11.  Func-
               tions 10 and 11 are specific to the hardware on Intel
               expanded memory boards and will not work correctly on all
               vendors' expanded memory boards.


































          EMM Functions                                                  57





          Function 11. Reserved



               In earlier versions of the Lotus/Intel/Microsoft Expanded
               Memory Specification, Function 11 returned a page transla-
               tion array.  This function is now reserved and new programs
               should not use it.

               Existing programs that use this function may still work
               correctly if the hardware is capable of supporting them. 
               However, programs that use Functions 16 through 30 in
               Version 4.0 of this specification must not use Functions 10
               and 11.  These functions won't work correctly if your
               program attempts to mix the use of the new functions
               (Functions 16 through 30) and Functions 10 and 11.  Func-
               tions 10 and 11 are specific to the hardware on Intel
               expanded memory boards and will not work correctly on all
               vendors' expanded memory boards.


































          EMM Functions                                                  58





          Function 12. Get Handle Count



          PURPOSE

               The Get Handle Count function returns the number of open EMM
               handles (including the operating system handle 0) in the
               system.


          CALLING PARAMETERS

               AH = 4Bh
                   Contains the Get Handle Count function.


          RESULTS

               These results are valid only if the status returned is zero.

               BX = total_open_emm_handles
                   Contains the number of open EMM handles [including the
                   operating system handle (0)].  This number will not
                   exceed 255.


          REGISTERS MODIFIED

               AX, BX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has returned the number of active EMM
                   handles.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfunction in the expanded
                   memory hardware.

               AH = 84h   NON-RECOVERABLE.
                   The function code passed to the memory manager is not
                   defined.




          EMM Functions                                                  59





          Function 12. Get Handle Count



          EXAMPLE

          total_open_emm_handles              DW ?

          MOV   AH,4Bh                        ; load function code
          INT   67h                           ; call the memory manger
          OR    AH,AH                         ; check EMM status
          JNZ   emm_err_handler               ; jump to error handler on   
                                              ; error
          MOV   total_open_emm_handles,BX     ; save total active handle   
                                              ; count






































          EMM Functions                                                  60





          Function 13. Get Handle Pages



          PURPOSE

               The Get Handle Pages function returns the number of pages
               allocated to a specific EMM handle.


          CALLING PARAMETERS

               AH = 4Ch
                   Contains the Get Handle Pages function.

               DX = emm_handle
                   Contains the EMM handle.


          RESULTS

               These results are valid only if the status returned is zero.

               BX = num_pages_alloc_to_emm_handle
                   Contains the number of logical pages allocated to the
                   specified EMM handle.  This number never exceeds 2048
                   because the memory manager allows a maximum of 2048
                   pages (32M bytes) of expanded memory.


          REGISTERS MODIFIED

               AX, BX


          STATUS

               AH = 0   SUCCESSFUL.
                   The manager has returned the number of pages allocated
                   to the EMM handle.

               AH = 80h   NON-RECOVERABLE.
                   The manager detected a malfunction in the memory manager
                   software.

               AH = 81h   NON-RECOVERABLE.
                   The manager detected a malfu